
#include "sys_usw_ipuc.h"
#include "../tsingma/sys_tsingma_ipuc_tcam.h"
#include "sys_nalpm2.h"
#include "sys_usw_ofb.h"
#include "sys_usw_opf.h"
#include "sys_usw_common.h"
#include "sys_usw_ftm.h"
#include "drv_api.h"
#include "sys_usw_register.h"
#include "sys_usw_wb_common.h"

#define _________Macro_________

#define _________Declaration_________

sys_nalpm2_master_t* g_sys_nalpm2_master[CTC_MAX_LOCAL_CHIP_NUM_PP] = {NULL};
extern sys_ipuc_master_t* p_usw_ipuc_master[];

#define __________________FUNC__________________

#define _____Common_____

int32
_sys_nalpm2_route_cmp_l0(uint8 lchip, sys_nalpm2_info_t* p_route_info_0, sys_nalpm2_info_t* p_route_info_1)
{
    uint32 key[4] = {0};

    if(!p_route_info_0 || !p_route_info_1)
    {
        return CTC_E_INVALID_PARAM;
    }

    if (p_route_info_0->ip_ver != p_route_info_1->ip_ver)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_0->vrf_id != p_route_info_1->vrf_id)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_1->route_masklen > p_route_info_0->route_masklen)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    sal_memcpy(key, p_route_info_0->ip, IP_ADDR_SIZE(p_route_info_0->ip_ver));

    if (CTC_IP_VER_4 == p_route_info_0->ip_ver)
    {
        IPV4_MASK(key[0], p_route_info_1->route_masklen)
    }
    else
    {
        IPV6_MASK(key, p_route_info_1->route_masklen)
    }

    if (0 != sal_memcmp(key, p_route_info_1->ip,
                        IP_ADDR_SIZE(p_route_info_0->ip_ver)))
    {
        return CTC_E_PARAM_CONFLICT;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_route_cmp_l1(uint8 lchip, sys_ipuc_info_t* p_route_info_0, sys_ipuc_info_t* p_route_info_1)
{
    if(!p_route_info_0 || !p_route_info_1)
    {
        return CTC_E_INVALID_PARAM;
    }

    if (SYS_IPUC_VER(p_route_info_0) != SYS_IPUC_VER(p_route_info_1))
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_0->vrf_id != p_route_info_1->vrf_id)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (p_route_info_0->masklen != p_route_info_1->masklen)
    {
        return CTC_E_PARAM_CONFLICT;
    }

    if (0 != sal_memcmp(&(p_route_info_0->ip), &(p_route_info_1->ip),
                        IP_ADDR_SIZE(SYS_IPUC_VER(p_route_info_0))))
    {
        return CTC_E_PARAM_CONFLICT;
    }

    return CTC_E_NONE;
}

uint8
_sys_nalpm2_root_mask_cmp_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    uint8 route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    uint8 i = 0;
    uint8 j = 0;

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL != p_tcam_item->p_l0_info_array[i][j] && NULL != p_tcam_item->p_l0_root_info)
            {
                if (p_tcam_item->p_l0_root_info->tcam_masklen == p_tcam_item->p_l0_info_array[i][j]->route_masklen)
                {
                    return TRUE;
                }
            }

            j++;

        } while (j < route_per_snake);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    return FALSE;
}

int32
_sys_nalpm2_route_match_l0(uint8 lchip, sys_nalpm2_info_t* p_l0_root_info, sys_nalpm2_info_t* p_l0_info)
{
    uint32 key1[4] = {0};
    uint32 key2[4] = {0};
    uint32 mask_pfx = 0;
    uint32 masklen = 0;

    if(!p_l0_root_info || !p_l0_info)
    {
        return CTC_E_INVALID_PARAM;
    }

    if(p_l0_root_info->tcam_masklen < p_l0_info->route_masklen)
    {
        masklen = p_l0_root_info->tcam_masklen;
    }
    else
    {
        masklen = p_l0_info->route_masklen;
    }

    if (CTC_IP_VER_4 == p_l0_root_info->ip_ver)
    {
        mask_pfx = g_sys_nalpm2_master[lchip]->len2pfx[masklen];
        if ((p_l0_root_info->ip[0] & mask_pfx) != (p_l0_info->ip[0] & mask_pfx))
        {
            return CTC_E_PARAM_CONFLICT;
        }
    }
    else
    {
        sal_memcpy(key1, p_l0_root_info->ip, sizeof(ipv6_addr_t));
        sal_memcpy(key2, p_l0_info->ip, sizeof(ipv6_addr_t));
        SYS_IPV6_IP_SORT(p_l0_root_info->ip_ver, key1);
        SYS_IPV6_IP_SORT(p_l0_root_info->ip_ver, key2);

        mask_pfx = g_sys_nalpm2_master[lchip]->len2pfx[masklen%32];

        if (sal_memcmp(key1, key2, (masklen / 32) * sizeof(uint32))
            || ((key1[masklen / 32] & mask_pfx) != (key2[masklen / 32] & mask_pfx)))
        {
            return CTC_E_PARAM_CONFLICT;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_route_match_l1(uint8 lchip, sys_nalpm2_info_t* p_l1_root_info, sys_ipuc_info_t* p_l1_info)
{
    uint32 key1[4] = {0};
    uint32 key2[4] = {0};
    uint32 mask_pfx = 0;
    uint32 masklen = 0;
    uint8 ip_ver = 0;

    if(!p_l1_root_info || !p_l1_info)
    {
        return CTC_E_INVALID_PARAM;
    }

    if(p_l1_root_info->tcam_masklen < p_l1_info->masklen)
    {
        masklen = p_l1_root_info->tcam_masklen;
    }
    else
    {
        masklen = p_l1_info->masklen;
    }

    ip_ver = CTC_FLAG_ISSET(p_l1_info->route_flag, SYS_IPUC_FLAG_IS_IPV6) ? CTC_IP_VER_6 : CTC_IP_VER_4;

    if (CTC_IP_VER_4 == ip_ver)
    {
        mask_pfx = g_sys_nalpm2_master[lchip]->len2pfx[masklen];
        if ((p_l1_root_info->ip[0] & mask_pfx) != (p_l1_info->ip.ipv4 & mask_pfx))
        {
            return CTC_E_PARAM_CONFLICT;
        }
    }
    else
    {
        sal_memcpy(key1, p_l1_root_info->ip, sizeof(ipv6_addr_t));
        sal_memcpy(key2, &(p_l1_info->ip), sizeof(ipv6_addr_t));
        SYS_IPV6_IP_SORT(ip_ver, key1);
        SYS_IPV6_IP_SORT(ip_ver, key2);

        mask_pfx = g_sys_nalpm2_master[lchip]->len2pfx[masklen%32];

        if (sal_memcmp(key1, key2, (masklen / 32) * sizeof(uint32))
            || ((key1[masklen / 32] & mask_pfx) != (key2[masklen / 32] & mask_pfx)))
        {
            return CTC_E_PARAM_CONFLICT;
        }

    }

    return CTC_E_NONE;
}

uint8
_sys_nalpm2_get_snake_route_num_l0(uint8 lchip, uint8 sram_type)
{
    uint8 num = 0;

    switch(sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V4_32:
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:
            num = NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V4];
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_64:
            num = NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V6_64];
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_128:
            num = NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V6_128];
            break;
        default:
            break;
    }

    return num;
}

uint8
_sys_nalpm2_get_snake_route_num_l1(uint8 lchip, uint8 sram_type)
{
    uint8 num = 0;

    switch(sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V4_32:
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:
            num = NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V4];
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_64:
            num = NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V6_64];
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_128:
            num = NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V6_128];
            break;
        default:
            break;
    }

    return num;
}

uint8
_sys_nalpm2_get_snake_bitwdith(uint8 lchip, uint8 sram_type)
{
    uint8 bit_width = 0;

    switch(sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V4_32:
            bit_width = 0x3F;
            break;
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:
            bit_width = 0xF;
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_64:
            bit_width = 0x7;
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_128:
             bit_width = 0x3;
            break;
        default:
            break;
    }

    return bit_width;
}

uint8
_sys_nalpm2_get_node_num(uint8 lchip, uint8 sram_type)
{
    uint8 node_num = 0;

    switch(sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V4_32:
            node_num = 6;
            break;
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:
            node_num = 4;
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_64:
            node_num = 3;
            break;
        case SYS_NALPM2_SRAM_TYPE_V6_128:
             node_num = 2;
            break;
        default:
            break;
    }

    return node_num;
}

int32
_sys_nalpm2_get_table_id_l0(uint8 lchip, uint8 type, uint8 snake_idx, uint32* p_tbl_id, uint32* p_tbl_id1)
{
    uint32 tbl_id = 0;
    uint32 tbl_id1 = 0;
    uint8 gid = 0;

    gid = snake_idx >= NALPM2_BUKCET_SNACK_PER_GRP_L0(lchip) ? 1 : 0;

    if (g_sys_nalpm2_master[lchip]->ipsa_enable)
    {
        tbl_id = NALPM2_SNAKE_TABLE_L0(lchip, 0, type);
        tbl_id1 = NALPM2_SNAKE_TABLE_L0(lchip, 1, type);
    }
    else
    {
        tbl_id = NALPM2_SNAKE_TABLE_L0(lchip, gid, type);
    }

    *p_tbl_id = tbl_id;
    *p_tbl_id1 = tbl_id1;

    return CTC_E_NONE;
}

int32
_sys_nalpm2_get_table_id_l1(uint8 lchip, uint8 type, uint8 snake_idx, uint32* p_tbl_id, uint32* p_tbl_id1)
{
    uint32 tbl_id = 0;
    uint32 tbl_id1 = 0;
    uint8 gid = 0;

    gid = snake_idx >= NALPM2_BUKCET_SNACK_PER_GRP_L1(lchip) ? 1 : 0;

    if (g_sys_nalpm2_master[lchip]->ipsa_enable)
    {
        tbl_id = NALPM2_SNAKE_TABLE_L1(lchip, 0, type);
        tbl_id1 = NALPM2_SNAKE_TABLE_L1(lchip, 1, type);
    }
    else
    {
        tbl_id = NALPM2_SNAKE_TABLE_L1(lchip, gid, type);
    }

    *p_tbl_id = tbl_id;
    *p_tbl_id1 = tbl_id1;

    return CTC_E_NONE;
}

int32
_sys_nalpm2_lkup_entry_l0(uint8 lchip, sys_nalpm2_info_t* p_l0_info, sys_nalpm2_route_store_info_t* p_lkp_rlt, sys_nalpm2_tcam_item_t *p_tcam_item)
{
    uint32 sram_idx = 0;
    uint8 find_valid_position = 0;
    uint8 find_void_position = 0;
    uint8 void_i = 0, void_j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 mask_temp1 = 0;
    uint8 sram_type = 0;
    uint8 mask_temp = 0;
    uint8 i = 0, j = 0;

    /* 0. prepare data */
    sram_type =  p_tcam_item->sram_type;
    sram_idx = p_tcam_item->sram_idx;

    /* 1. find position or alloc position */
    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        /* 1.1 alloc position */
        if (NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i] == 0)
        {
            if (!find_void_position)
            {
                find_void_position = 1;
                void_i = i;
                void_j = 0;
            }
            i++;
            continue;
        }

        j = 0;
        do
        {
            /* 1.2 find position */
            if (p_tcam_item->p_l0_info_array[i][j] && !p_l0_info->tcam_masklen)
            {
                /* 1.2.1 entry exist, find exact route */
                if (0 == _sys_nalpm2_route_cmp_l0(lchip, p_l0_info, p_tcam_item->p_l0_info_array[i][j]))
                {
                    mask_temp1 = p_tcam_item->p_l0_info_array[i][j]->route_masklen;
                    if (mask_temp1 < mask_temp)
                    {
                        j++;
                        continue;
                    }
                    p_lkp_rlt->sram_hit[LEVEL0] = TRUE;
                    p_lkp_rlt->snake_idx[LEVEL0] = i;
                    p_lkp_rlt->entry_offset[LEVEL0] = j;
                    mask_temp = mask_temp1;
                    find_valid_position = 1;
                }
            }
            /* 1.3 alloc position */
            else if( (!CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i], j)) && (!find_void_position) && (!find_valid_position))
            {
               /*entry not exist*/
               find_void_position = 1;
               void_i = i;
               void_j = j;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    /* 2. not found position, use alloced position */
    if (p_lkp_rlt->sram_hit[LEVEL0] == FALSE)
    {
        if (find_void_position)
        {
            p_lkp_rlt->snake_idx[LEVEL0] = void_i;
            p_lkp_rlt->entry_offset[LEVEL0] = void_j;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_lkup_entry_l1(uint8 lchip, sys_ipuc_info_t* p_l1_info, sys_nalpm2_route_store_info_t* p_lkp_rlt, sys_nalpm2_l0_item_t* p_l0_item)
{
    uint32 sram_idx = 0;
    uint8 find_valid_position = 0;
    uint8 void_i = 0, void_j = 0;
    uint8 find_void_position = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 mask_temp1 = 0;
    uint8 sram_type = 0;
    uint8 mask_temp = 0;
    uint8 i = 0, j = 0;

    /* 0. prepare data */
    sram_type = p_l0_item->sram_type;
    sram_idx = p_l0_item->sram_idx;

    /* 1. find position or alloc position */
    route_per_snake = _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        /* 1.1 alloc position */
        if (NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap[i] == 0)
        {
            if (!find_void_position)
            {
                find_void_position = 1;
                void_i = i;
                void_j = 0;
            }
            i++;
            continue;
        }

        j = 0;
        do
        {
            /* 1.2 find position */
            if (p_l0_item->p_l1_info_array[i][j])
            {
                /* 1.2.1 entry exist, find exact route */
                if (0 == _sys_nalpm2_route_cmp_l1(lchip, p_l1_info, p_l0_item->p_l1_info_array[i][j]))
                {
                    mask_temp1 = p_l0_item->p_l1_info_array[i][j]->masklen;
                    if (mask_temp1 < mask_temp)
                    {
                        j++;
                        continue;
                    }
                    p_lkp_rlt->sram_hit[LEVEL1] = TRUE;
                    p_lkp_rlt->snake_idx[LEVEL1] = i;
                    p_lkp_rlt->entry_offset[LEVEL1] = j;
                    mask_temp = mask_temp1;
                    find_valid_position = 1;
                }
            }
            /* 1.3 alloc position */
            else if( (!CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap[i], j)) && (!find_void_position) && (!find_valid_position))
            {
               /*entry not exist*/
               find_void_position = 1;
               void_i = i;
               void_j = j;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    /* 2. not found position, use alloced position */
    if (p_lkp_rlt->sram_hit[LEVEL1] == FALSE)
    {
        if (find_void_position)
        {
            p_lkp_rlt->snake_idx[LEVEL1] = void_i;
            p_lkp_rlt->entry_offset[LEVEL1] = void_j;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_route_lkp_l0(uint8 lchip, sys_nalpm2_info_t* p_nalpm_info, sys_nalpm2_route_store_info_t* p_lkp_rlt)
{
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    trie_node_t* p_node = NULL;
    uint32* p_trie_key = NULL;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* -1. valid check */
    if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][p_nalpm_info->ip_ver][p_nalpm_info->vrf_id])
    {
        return CTC_E_NOT_EXIST;
    }

    /* 0. prepare data */
    p_trie_key = mem_malloc2(MEM_IPUC_MODULE, IP_ADDR_SIZE(p_nalpm_info->ip_ver), uint32);
    if(!p_trie_key)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_trie_key, 0 ,(IP_ADDR_SIZE(p_nalpm_info->ip_ver)));
    sal_memcpy(p_trie_key, p_nalpm_info->ip, (IP_ADDR_SIZE(p_nalpm_info->ip_ver)));
    SYS_IPV6_IP_SORT(p_nalpm_info->ip_ver, p_trie_key);

    /* 1. lookup tcam item trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_find_lpm(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][p_nalpm_info->ip_ver][p_nalpm_info->vrf_id],
                                            p_trie_key, p_nalpm_info->route_masklen, &p_node, 1), ret, END);
    if(p_node == NULL)
    {
         ret = CTC_E_NOT_EXIST;
         goto END;
    }

    /* 2. parser data */
    p_trie_tcam_item =(sys_nalpm2_trie_tcam_item_t*)p_node;
    p_lkp_rlt->p_tcam_item = &p_trie_tcam_item->tcam_item;
    p_lkp_rlt->total_skip_len = p_node->total_skip_len;
    p_lkp_rlt->sram_hit[LEVEL0] = FALSE;
    p_lkp_rlt->tcam_hit = TRUE;

    /* 3. lookup L0 sram */
    CTC_ERROR_GOTO(_sys_nalpm2_lkup_entry_l0(lchip, p_nalpm_info, p_lkp_rlt, p_lkp_rlt->p_tcam_item), ret, END);

    /* 4. lookup L1 sram */
    if (p_lkp_rlt->p_tcam_item->p_l0_info_array[p_lkp_rlt->snake_idx[LEVEL0]][p_lkp_rlt->entry_offset[LEVEL0]] && p_lkp_rlt->sram_hit[LEVEL0])
    {
        sys_ipuc_info_t ipuc_info;

        /* 4.0 prepare data */
        sal_memset(&ipuc_info, 0, sizeof(sys_ipuc_info_t));

        if (p_nalpm_info->ip_ver == CTC_IP_VER_6)
        {
            CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_IS_IPV6);
        }
        ipuc_info.masklen = p_nalpm_info->route_masklen;
        ipuc_info.vrf_id = p_nalpm_info->vrf_id;
        sal_memcpy(&(ipuc_info.ip), p_nalpm_info->ip, IP_ADDR_SIZE(p_nalpm_info->ip_ver));

        p_lkp_rlt->p_l0_item = p_lkp_rlt->p_tcam_item->p_l0_info_array[p_lkp_rlt->snake_idx[LEVEL0]][p_lkp_rlt->entry_offset[LEVEL0]]->p_l0_item;

        /* 4.1 lookup L1 sram */
        CTC_ERROR_GOTO(_sys_nalpm2_lkup_entry_l1(lchip, &ipuc_info, p_lkp_rlt, p_lkp_rlt->p_l0_item), ret, END);
    }
END:
    if(p_trie_key)
    {
        mem_free(p_trie_key);
    }
    return ret;
}

int32
_sys_nalpm2_route_lkp_l1(uint8 lchip, sys_nalpm2_info_t* p_nalpm_info, sys_nalpm2_route_store_info_t* p_lkp_rlt)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    trie_node_t* p_node = NULL;
    uint32* p_trie_key = NULL;
    sys_ipuc_info_t ipuc_info;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* -1. valid check */
    if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_nalpm_info->ip_ver][p_nalpm_info->vrf_id])
    {
        return CTC_E_NOT_EXIST;
    }

    /* 0. prepare data */
    /* 0.1 p_trie_key */
    p_trie_key = mem_malloc2(MEM_IPUC_MODULE, IP_ADDR_SIZE(p_nalpm_info->ip_ver), uint32);
    if(!p_trie_key)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_trie_key, 0 ,(IP_ADDR_SIZE(p_nalpm_info->ip_ver)));
    sal_memcpy(p_trie_key, p_nalpm_info->ip, (IP_ADDR_SIZE(p_nalpm_info->ip_ver)));
    SYS_IPV6_IP_SORT(p_nalpm_info->ip_ver, p_trie_key);

    /* 0.2 ipuc_info */
    sal_memset(&ipuc_info, 0, sizeof(sys_ipuc_info_t));
    if (p_nalpm_info->ip_ver == CTC_IP_VER_6)
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_IS_IPV6);
    }
    ipuc_info.vrf_id = p_nalpm_info->vrf_id;
    ipuc_info.masklen = p_nalpm_info->route_masklen;
    sal_memcpy(&(ipuc_info.ip), p_nalpm_info->ip, IP_ADDR_SIZE(p_nalpm_info->ip_ver));

    /* 1. lookup l0 item trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_find_lpm(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_nalpm_info->ip_ver][p_nalpm_info->vrf_id],
                                            p_trie_key, p_nalpm_info->route_masklen, &p_node, 1), ret, END);
    if(p_node == NULL)
    {
         ret = CTC_E_NOT_EXIST;
         goto END;
    }

    /* 2. parser data */
    p_trie_l0_item =(sys_nalpm2_trie_l0_item_t*)p_node;
    p_lkp_rlt->p_l0_item = &p_trie_l0_item->l0_item;
    p_lkp_rlt->sram_hit[LEVEL1] = FALSE;
    p_lkp_rlt->total_skip_len = p_node->total_skip_len;
    p_lkp_rlt->p_tcam_item = p_lkp_rlt->p_l0_item->p_tcam_item;

    if (p_lkp_rlt->p_tcam_item == NULL)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "LEVEL1:tcam item not found!!\n");
        ret = CTC_E_NOT_EXIST;
        goto END;
    }

    /* 3. lookup L1 sram */
    CTC_ERROR_GOTO(_sys_nalpm2_lkup_entry_l1(lchip, &ipuc_info, p_lkp_rlt, p_lkp_rlt->p_l0_item), ret, END);

END:
    if(p_trie_key)
    {
        mem_free(p_trie_key);
    }
    return ret;
}

int32
_sys_nalpm2_sram_entry_is_full_l0(uint8 lchip, sys_nalpm2_tcam_item_t *p_tcam_item, uint8 new_root)
{
    uint8 node_num = _sys_nalpm2_get_node_num(lchip, p_tcam_item->sram_type) * NALPM2_BUKCET_SNAKE_NUM_L0(lchip);
    uint8 valid_cnt = 0;

    /* 1. get valid cnt */
    valid_cnt = p_tcam_item->trie->trie->count;

    /* 2. whether has default prefix node. if has not default prefix node, the full num is total trie node num minus 1 */
    if (valid_cnt == (node_num - 1))
    {
        if (new_root || _sys_nalpm2_root_mask_cmp_l0(lchip, p_tcam_item))
        {
            return FALSE;
        }
        else
        {
            return TRUE;
        }
    }
    else if (valid_cnt == node_num)
    {
        return TRUE;
    }

    return FALSE;
}

int32
_sys_nalpm2_sram_entry_is_full_l1(uint8 lchip, sys_nalpm2_l0_item_t *p_l0_item)
{
    uint8 i = 0;

    do
    {
        if (NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i] != _sys_nalpm2_get_snake_bitwdith(lchip, p_l0_item->sram_type))
        {
            return FALSE;
        }

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return TRUE;
}

int32
_sys_nalpm2_search_best_route_in_sram_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_info_t* p_l0_root_info, sys_nalpm2_info_t** pp_best_route)
{
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 best_snake = 0xff;
    uint8 best_offset = 0xff;
    uint8 i = 0, j = 0;

    *pp_best_route = NULL;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        if(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i] == 0)
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (NULL != p_tcam_item->p_l0_info_array[i][j])
            {
                if (p_l0_root_info->tcam_masklen <= p_tcam_item->p_l0_info_array[i][j]->tcam_masklen)
                {
                    j++;
                    continue;
                }

                if (_sys_nalpm2_route_match_l0(lchip, p_l0_root_info, p_tcam_item->p_l0_info_array[i][j]))
                {
                    j++;
                    continue;
                }

                if (0xff == best_snake)
                {
                    best_snake = i;
                    best_offset = j;
                }

                if (p_tcam_item->p_l0_info_array[i][j]->tcam_masklen > p_tcam_item->p_l0_info_array[best_snake][best_offset]->tcam_masklen)
                {
                    best_snake = i;
                    best_offset = j;
                }
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    if(best_snake != 0xff)
    {
        *pp_best_route = p_tcam_item->p_l0_info_array[best_snake][best_offset];
        return CTC_E_NONE;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_search_best_route_in_sram_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_info_t* p_l1_root_info, sys_ipuc_info_t** pp_best_route)
{
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 best_snake = 0xff;
    uint8 best_offset = 0xff;
    uint8 i = 0, j = 0;

    *pp_best_route = NULL;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l1(lchip, p_l0_item->sram_type);
    snake_entry_cnt = route_per_snake;

    /* whether the l1_root_AD is the covered route */
    if(p_l0_item->p_l1_root_AD)
    {
        if(0 == _sys_nalpm2_route_match_l1(lchip, p_l1_root_info, p_l0_item->p_l1_root_AD))
        {
            *pp_best_route = p_l0_item->p_l1_root_AD;
        }
    }

    i = 0;
    do
    {
        if(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i] == 0)
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (NULL != p_l0_item->p_l1_info_array[i][j])
            {
                if (p_l1_root_info->tcam_masklen <= p_l0_item->p_l1_info_array[i][j]->masklen)
                {
                    j++;
                    continue;
                }

                if (_sys_nalpm2_route_match_l1(lchip, p_l1_root_info, p_l0_item->p_l1_info_array[i][j]))
                {
                    j++;
                    continue;
                }

                if (0xff == best_snake)
                {
                    best_snake = i;
                    best_offset = j;
                }

                if (p_l0_item->p_l1_info_array[i][j]->masklen > p_l0_item->p_l1_info_array[best_snake][best_offset]->masklen)
                {
                    best_snake = i;
                    best_offset = j;
                }
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    if(best_snake != 0xff)
    {
        *pp_best_route = p_l0_item->p_l1_info_array[best_snake][best_offset];
        return CTC_E_NONE;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_find_best_position_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, uint8 masklen, uint8* snake_idx, uint8* offset)
{
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 i = 0, j = 0;

    *snake_idx = 0xff;
    *offset = 0xff;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        if (NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i] == _sys_nalpm2_get_snake_bitwdith(lchip, p_tcam_item->sram_type))
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (!CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j))
            {
                *snake_idx = i;
                *offset = j;
                return CTC_E_NONE;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    return (*snake_idx == 0xff) ? CTC_E_NO_RESOURCE : CTC_E_NONE;
}

int32
_sys_nalpm2_find_best_position_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, uint8 masklen, uint8* snake_idx, uint8* offset)
{
    uint8 i = 0, j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;

    *snake_idx = 0xff;
    *offset = 0xff;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l1(lchip, p_l0_item->sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        if (NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i] == _sys_nalpm2_get_snake_bitwdith(lchip, p_l0_item->sram_type))
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (!CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i], j))
            {
                *snake_idx = i;
                *offset = j;
                return CTC_E_NONE;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return (*snake_idx == 0xff) ? CTC_E_NO_RESOURCE : CTC_E_NONE;
}

int32
_sys_nalpm2_free_route_node_l0(trie_node_t* node, void *data)
{
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_info_t *p_l0_info = NULL;

    p_trie_l0_info = (sys_nalpm2_trie_l0_info_t* )node;

    if (p_trie_l0_info->node.type != INTERNAL)
    {
        p_l0_info = p_trie_l0_info->p_l0_info;
        mem_free(p_l0_info);
    }

    mem_free(p_trie_l0_info);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_free_route_node_l1(trie_node_t* node, void *data)
{
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info = NULL;

    p_trie_l1_info = (sys_nalpm2_trie_l1_info_t* )node;

    mem_free(p_trie_l1_info);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_free_prefix_node_l0(trie_node_t * p_node, void * user_data)
{
    sys_nalpm2_trie_tcam_item_t * p_trie_tcam_item = NULL;
    p_trie_tcam_item = CONTAINER_OF(p_node, sys_nalpm2_trie_tcam_item_t, node);
    if (p_node == NULL)
    {
        return CTC_E_NONE;
    }
    if (INTERNAL == p_trie_tcam_item->node.type)
    {
        mem_free(p_trie_tcam_item);
        return CTC_E_NONE;
    }
    sys_nalpm_trie_traverse(p_trie_tcam_item->tcam_item.trie->trie, _sys_nalpm2_free_route_node_l0, NULL, _TRIE_POSTORDER_TRAVERSE);
    mem_free(p_trie_tcam_item->tcam_item.trie);
    mem_free(p_trie_tcam_item->tcam_item.p_l0_root_info);
    mem_free(p_trie_tcam_item);
    return CTC_E_NONE;
}

int32
_sys_nalpm2_free_prefix_node_l1(trie_node_t * p_node, void * user_data)
{
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    p_trie_l0_item = CONTAINER_OF(p_node, sys_nalpm2_trie_l0_item_t, node);
    if (p_node == NULL)
    {
        return CTC_E_NONE;
    }
    if (INTERNAL == p_trie_l0_item->node.type)
    {
        mem_free(p_trie_l0_item);
        return CTC_E_NONE;
    }
    sys_nalpm_trie_traverse(p_trie_l0_item->l0_item.trie->trie, _sys_nalpm2_free_route_node_l1, NULL, _TRIE_POSTORDER_TRAVERSE);
    mem_free(p_trie_l0_item->l0_item.trie);
    mem_free(p_trie_l0_item);
    return CTC_E_NONE;
}

#define ______HASH______

int32
_sys_nalpm2_ipuc_hash_make_l0(sys_nalpm2_tcam_ad_t* p_tcam_ad)
{
    return ctc_hash_caculate(sizeof(uint32), &(p_tcam_ad->tcam_idx));
}

int32
_sys_nalpm2_ipuc_hash_make_l1(sys_nalpm2_l0_ad_t* p_l0_ad)
{
    return ctc_hash_caculate((sizeof(uint8) * 5), &(p_l0_ad->sram_idx));
}

int32
_sys_nalpm2_ipuc_hash_cmp_l0(sys_nalpm2_tcam_ad_t* p_tcam_ad_0, sys_nalpm2_tcam_ad_t* p_tcam_ad_1)
{
    if (p_tcam_ad_0->tcam_idx != p_tcam_ad_1->tcam_idx)
    {
        return FALSE;
    }

    return TRUE;
}

int32
_sys_nalpm2_ipuc_hash_cmp_l1(sys_nalpm2_l0_ad_t* p_l0_ad_0, sys_nalpm2_l0_ad_t* p_l0_ad_1)
{
    if (p_l0_ad_0->sram_idx != p_l0_ad_1->sram_idx)
    {
        return FALSE;
    }

    if (p_l0_ad_0->snake_idx != p_l0_ad_1->snake_idx)
    {
        return FALSE;
    }

    if (p_l0_ad_0->entry_offset != p_l0_ad_1->entry_offset)
    {
        return FALSE;
    }

    if (p_l0_ad_0->sram_type != p_l0_ad_1->sram_type)
    {
        return FALSE;
    }

    return TRUE;
}

int32
_sys_nalpm2_pivot_hash_make_l0(sys_nalpm2_tcam_item_t* p_tcam_item)
{
    uint32 index = (p_tcam_item->sram_idx<<16 | p_tcam_item->sub_bkt);
    return ctc_hash_caculate(sizeof(uint32), &index);
}

int32
_sys_nalpm2_pivot_hash_make_l1(sys_nalpm2_l0_item_t* p_l0_item)
{
    uint32 index = (p_l0_item->sram_idx<<16 | p_l0_item->sub_bkt);
    return ctc_hash_caculate(sizeof(uint32), &index);
}

int32
_sys_nalpm2_pivot_hash_cmp_l0(sys_nalpm2_tcam_item_t* p_db_tcam_item, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    if (p_db_tcam_item->sram_idx == p_tcam_item->sram_idx && p_db_tcam_item->sub_bkt == p_tcam_item->sub_bkt)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}

int32
_sys_nalpm2_pivot_hash_cmp_l1(sys_nalpm2_l0_item_t* p_db_tcam_item, sys_nalpm2_l0_item_t* p_l0_item)
{
    if (p_db_tcam_item->sram_idx == p_l0_item->sram_idx && p_db_tcam_item->sub_bkt == p_l0_item->sub_bkt)
    {
        return TRUE;
    }
    else
    {
        return FALSE;
    }
}


int32
_sys_nalpm2_hash_free_node_data(void* node_data, void* user_data)
{

    mem_free(node_data);

    return CTC_E_NONE;
}

#define ______TCAM______

int32
_sys_nalpm2_tcam_idx_alloc(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    sys_ipuc_tcam_data_t tcam_data = {0};
    uint8 ip_ver = p_tcam_item->p_l0_root_info->ip_ver;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    tcam_data.masklen = p_tcam_item->p_l0_root_info->tcam_masklen;
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
    tcam_data.info = (void*)(p_tcam_item);
    tcam_data.ipuc_param = p_ipuc_param;

    if(p_usw_ipuc_master[lchip]->lpm_tcam_spec[ip_ver] != 0
     && p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] >= p_usw_ipuc_master[lchip]->lpm_tcam_spec[ip_ver])
    {
        return CTC_E_NO_RESOURCE;
    }

    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        tcam_data.key_index = p_tcam_item->tcam_idx;
        tcam_data.masklen = p_tcam_item->p_l0_root_info->tcam_masklen;
    }

    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->alloc_tcam_key_index(lchip, &tcam_data));

    p_tcam_item->tcam_idx = tcam_data.key_index;

    if(ip_ver && IS_SHORT_KEY(0, p_tcam_item->tcam_idx))
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] += 2;
    }
    else if(ip_ver)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] += 4;
    }
    else
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver]++;
    }

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "%s(), tcam_idx=[%u]\n",__FUNCTION__, p_tcam_item->tcam_idx);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_tcam_idx_free(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    sys_ipuc_tcam_data_t tcam_data = {0};
    uint8 ip_ver = p_tcam_item->p_l0_root_info->ip_ver;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "%s(), tcam_idx=[%u]\n",__FUNCTION__, p_tcam_item->tcam_idx);

    tcam_data.masklen = p_tcam_item->p_l0_root_info->tcam_masklen;
    tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
    tcam_data.key_index = p_tcam_item->tcam_idx;
    tcam_data.ipuc_param = p_ipuc_param;
    tcam_data.info = (void*)(p_tcam_item);

    CTC_ERROR_RETURN(MCHIP_IPUC(lchip)->free_tcam_key_index(lchip, &tcam_data));

    if(ip_ver && IS_SHORT_KEY(0, p_tcam_item->tcam_idx))
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] -= 2;
    }
    else if(ip_ver)
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver] -= 4;
    }
    else
    {
        p_usw_ipuc_master[lchip]->lpm_tcam_used_cnt[ip_ver]--;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_write_tcam(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_ipuc_opt_type_t opt, uint32 update_ad_idx)
{
    sys_ipuc_tcam_key_t key;
    sys_ipuc_tcam_ad_t ad;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = p_tcam_item->p_l0_root_info->ip_ver;

    if(DO_ADD == opt || DO_UPDATE == opt)
    {
        sal_memset(&ad, 0, sizeof(ad));
        ad.tcamAd_key_idx = p_tcam_item->tcam_idx;
        ad.lpmPipelineValid = 1;
        ad.pointer = (p_tcam_item->sram_idx);
        ad.nexthop = (DO_UPDATE == opt) ? update_ad_idx : p_tcam_item->p_l0_root_info->ad_idx;
        p_tcam_item->p_l0_root_info->ad_idx = ad.nexthop;

        CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_write_ad2hw(lchip, ip_ver, SYS_PRIVATE_MODE, &ad, opt));
    }

    if(opt != DO_UPDATE)
    {
        sal_memset(&key, 0, sizeof(key));
        sal_memcpy(&key.ip, p_tcam_item->p_l0_root_info->ip, IP_ADDR_SIZE(ip_ver));
        key.key_idx = p_tcam_item->tcam_idx;
        key.mask_len = p_tcam_item->p_l0_root_info->tcam_masklen;
        key.vrfId = p_tcam_item->p_l0_root_info->vrf_id;
        key.vrfId_mask =  0x1FFF;

        CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_write_key2hw(lchip, ip_ver, SYS_PRIVATE_MODE, &key, opt));
    }

    return ret;
}

int32
_sys_nalpm2_read_tcam(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, uint32* p_ad_idx)
{
    sys_ipuc_tcam_ad_t ad;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = p_tcam_item->p_l0_root_info->ip_ver;

    sal_memset(&ad, 0, sizeof(ad));
    ad.tcamAd_key_idx = p_tcam_item->tcam_idx;

    CTC_ERROR_RETURN(sys_tsingma_ipuc_tcam_read_ad( lchip, ip_ver, SYS_PRIVATE_MODE, &ad));

    *p_ad_idx = ad.nexthop;

    return ret;
}

#define _______SRAM_______

int32
_sys_nalpm2_sram_idx_share_l1(uint8 lchip, uint8 fmt, uint32* p_sram_idx)
{
    sys_nalpm2_bucket_l1_t* p_bucket_l1 = NULL;
    uint8 find = 0;
    uint8 i = 0;

    i = 1;
    do
    {
        p_bucket_l1 = (sys_nalpm2_bucket_l1_t*)ctc_list_pointer_head(&NALPM2_BUCKET_L1(lchip).bkt_use_list[i]);

        do
        {
            if (NULL == p_bucket_l1)
            {
                break;
            }

            if (p_bucket_l1->fmt != fmt)
            {
                p_bucket_l1 = (sys_nalpm2_bucket_l1_t*)ctc_list_pointer_next((ctc_list_pointer_node_t*)p_bucket_l1);
                continue;
            }

            if (p_bucket_l1->is_root)
            {
                p_bucket_l1 = (sys_nalpm2_bucket_l1_t*)ctc_list_pointer_next((ctc_list_pointer_node_t*)p_bucket_l1);
                continue;
            }

            if (p_bucket_l1->sub_bkt < g_sys_nalpm2_master[lchip]->bucket_num)
            {
                find = 1;
                break;
            }

            p_bucket_l1 = (sys_nalpm2_bucket_l1_t*)ctc_list_pointer_next((ctc_list_pointer_node_t*)p_bucket_l1);

        } while (p_bucket_l1);

        if (find)
        {
            break;
        }

        i++;

    } while (i < NALPM2_BUCKET_FMT_MAX_L1(lchip, fmt));

    if (p_bucket_l1 && p_bucket_l1->sub_bkt < g_sys_nalpm2_master[lchip]->bucket_num)
    {
        *p_sram_idx = p_bucket_l1->sram_idx;

        return CTC_E_NONE;
    }

    return CTC_E_NO_RESOURCE;
}


int32
_sys_nalpm2_sram_idx_alloc_l0(uint8 lchip, uint8 ip_ver, uint16* p_sram_idx, uint8* sub_idx, uint8 is_root)
{
    sys_usw_opf_t opf;
    int32 ret = CTC_E_NONE;
    uint32 block_size = 1;
    uint32 sram_idx = 0;
    uint8 fmt = NALPM2_FORMAT(lchip, ip_ver);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    CTC_PTR_VALID_CHECK(p_sram_idx);

    /* 0. prepare data */
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;
    opf.pool_index = LEVEL0;
    opf.multiple = 1;

    /* 1. alloc sram index */
    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        CTC_ERROR_RETURN(sys_usw_opf_alloc_offset_from_position(lchip, &opf, block_size, *p_sram_idx));
    }
    else
    {
        CTC_ERROR_RETURN((sys_usw_opf_alloc_offset(lchip, &opf, block_size, &sram_idx)));
    }

    /* 2. update bucket stats */
    NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).sram_idx = sram_idx;
    NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).fmt = fmt;
    NALPM2_BUCKET_L0(lchip).bkt_cnt++;
    NALPM2_BUCKET_L0(lchip).bkt_usage[fmt]++;

    /* 3. set output data */
    *sub_idx = NALPM2_BUCKET_SUB_BKT_L0(lchip, sram_idx);
    *p_sram_idx = (uint16)sram_idx;

    return ret;
}

int32
_sys_nalpm2_sram_idx_alloc_l1(uint8 lchip, uint8 ip_ver, uint16* p_sram_idx, uint8* sub_idx, uint8 is_root)
{
    sys_usw_opf_t opf;
    int32 ret = CTC_E_NONE;
    uint32 block_size = 1;
    uint32 sram_idx = 0;
    uint8 fmt = NALPM2_FORMAT(lchip, ip_ver);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    CTC_PTR_VALID_CHECK(p_sram_idx);

    /* 0. prepare data */
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;
    opf.pool_index = LEVEL1;
    opf.multiple = 1;

    /* 1. alloc sram index */
    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        CTC_ERROR_RETURN(sys_usw_opf_alloc_offset_from_position(lchip, &opf, block_size, *p_sram_idx));
    }
    else
    {
        /* 1.1 set share bkt index for v6 address */
        if (!is_root)
        {
            ret = _sys_nalpm2_sram_idx_share_l1(lchip, fmt, &sram_idx);
            if (ret == CTC_E_NO_RESOURCE)
            {
                CTC_ERROR_RETURN(sys_usw_opf_alloc_offset(lchip, &opf, block_size, &sram_idx));
                ret = CTC_E_NONE;
            }
        }
        /* 1.2 alloc sram index */
        else
        {
            CTC_ERROR_RETURN(sys_usw_opf_alloc_offset(lchip, &opf, block_size, &sram_idx));
        }
    }

    /* 2. update bucket stats */
    NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx)++;
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).sram_idx = sram_idx;
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).fmt = fmt;

    if (NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx) == 1)
    {
        NALPM2_BUCKET_L1(lchip).bkt_cnt++;
        NALPM2_BUCKET_L1(lchip).bkt_usage[fmt]++;
    }

    /* 3. set output data */
    *sub_idx = NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx) - 1;
    *p_sram_idx = (uint16)sram_idx;

    return ret;
}

int32
_sys_nalpm2_sram_idx_free_l0(uint8 lchip, uint16 sram_idx, uint8 ip_ver)
{
    sys_usw_opf_t opf;
    uint8 fmt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = LEVEL0;
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;

    if (NALPM2_BUCKET_SUB_BKT_L0(lchip, sram_idx))
    {
        NALPM2_BUCKET_SUB_BKT_L0(lchip, sram_idx)--;
    }

    if (NALPM2_BUCKET_SUB_BKT_L0(lchip, sram_idx) != 0)
    {
        return CTC_E_NONE;
    }

    fmt = NALPM2_FORMAT(lchip, ip_ver);
    NALPM2_BUCKET_L0(lchip).bkt_cnt--;
    NALPM2_BUCKET_L0(lchip).bkt_usage[fmt]--;

    return sys_usw_opf_free_offset(lchip, &opf, 1, sram_idx);
}

int32
_sys_nalpm2_sram_idx_free_l1(uint8 lchip, uint16 sram_idx, uint8 ip_ver)
{
    sys_usw_opf_t opf;
    uint8 fmt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = LEVEL1;
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;

    if (NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx))
    {
        NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx)--;
    }

    if (NALPM2_BUCKET_SUB_BKT_L1(lchip, sram_idx) != 0)
    {
        return CTC_E_NONE;
    }

    fmt = NALPM2_FORMAT(lchip, ip_ver);
    NALPM2_BUCKET_L1(lchip).bkt_cnt--;
    NALPM2_BUCKET_L1(lchip).bkt_usage[fmt]--;

    return sys_usw_opf_free_offset(lchip, &opf, 1, sram_idx);
}

int32
_sys_nalpm2_write_sram_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_info_t* p_l0_info, uint8 snake_idx, uint8 entry_idx, uint8 is_update, void* p_data, void* p_data_mask)
{
    sys_nalpm2_sram_entry_type_t type = p_tcam_item->sram_type;
    uint32 DsNeoLpmMemorySnake[12] = {0};
    uint32 DsNeoLpmMemorySnake_mask[12] = {0};
    void* ptr = DsNeoLpmMemorySnake;
    void* ptr_mask = DsNeoLpmMemorySnake_mask;
    uint32* p_hw_ipaddr = 0;
    uint32 ip_mask[4] = {0};
    uint32 masklen = p_l0_info->route_masklen;
    uint32 ad_index = p_l0_info->ad_idx;
    uint32 tbl_id = 0, tbl_id1 = 0;
    uint32 bucketSel = 0;
    uint32 hw_idx = 0;
    uint32 cmd = 0;
    uint8 step = 0;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(ip_mask, 0xFF, sizeof(uint32) * 4);

    ptr = (p_data) ? p_data : DsNeoLpmMemorySnake;
    ptr_mask = (p_data_mask) ? p_data_mask : DsNeoLpmMemorySnake_mask;

    if (!p_data)
    {
        _sys_nalpm2_get_table_id_l0(lchip, type, snake_idx, &tbl_id, &tbl_id1);
        hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item->sram_idx, snake_idx);
        #if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
        #endif
    }

    if(!masklen && ad_index) /* for add /0 node */
    {
        bucketSel = 1;
    }

    switch (type)
    {
        case SYS_NALPM2_SRAM_TYPE_V6_64:
        {
            ipv6_addr_t ipv6_tmp;

            sal_memset(&ipv6_tmp, 0, sizeof(ipv6_addr_t));

            step = DsNeoLpmIpv6Bit64Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit64Snake_entry_0_ipAddr_f;

            ipv6_tmp[0] = p_l0_info->ip[2];
            ipv6_tmp[1] = p_l0_info->ip[3];

            if (!is_update)
            {
                /* 1. data */
                SetDsNeoLpmIpv6Bit64Snake(A, entry_0_ipAddr_f + step*(entry_idx%3), ptr, ipv6_tmp);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_maskLen_f + step*(entry_idx%3), ptr, masklen);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr, bucketSel);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sub_bkt : 0);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sram_idx : 0);

                /* 2. mask */
                SetDsNeoLpmIpv6Bit64Snake(A, entry_0_ipAddr_f + step*(entry_idx%3), ptr_mask, ip_mask);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_maskLen_f + step*(entry_idx%3), ptr_mask, 0xFF);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv6Bit64Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr_mask, 0xFFFF);
            }

            /* 1. data */
            SetDsNeoLpmIpv6Bit64Snake(V, entryType_f, ptr, type);
            SetDsNeoLpmIpv6Bit64Snake(V, entry_0_nexthop_f + step*(entry_idx % 3), ptr, ad_index);

            /* 2. mask */
            SetDsNeoLpmIpv6Bit64Snake(V, entryType_f, ptr_mask, 0x7);
            SetDsNeoLpmIpv6Bit64Snake(V, entry_0_nexthop_f + step*(entry_idx % 3), ptr_mask, 0x3FFFF);

            break;
        }
        case SYS_NALPM2_SRAM_TYPE_V6_128:
            step = DsNeoLpmIpv6Bit128Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit128Snake_entry_0_ipAddr_f;

            if (!is_update)
            {
                /* 1. data */
                SetDsNeoLpmIpv6Bit128Snake(A, entry_0_ipAddr_f+ step*(entry_idx&0x1), ptr, p_l0_info->ip);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_maskLen_f+ step*(entry_idx&0x1), ptr, masklen);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr, bucketSel);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sub_bkt : 0);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sram_idx : 0);

                /* 2. mask */
                SetDsNeoLpmIpv6Bit128Snake(A, entry_0_ipAddr_f+ step*(entry_idx&0x1), ptr_mask, ip_mask);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_maskLen_f+ step*(entry_idx&0x1), ptr_mask, 0xFF);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv6Bit128Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr_mask, 0xFFFF);
            }
            /* 1. data */
            SetDsNeoLpmIpv6Bit128Snake(V, entryType_f, ptr, type);
            SetDsNeoLpmIpv6Bit128Snake(V, entry_0_nexthop_f + step*(entry_idx&0x1), ptr, ad_index);

            /* 2. mask */
            SetDsNeoLpmIpv6Bit128Snake(V, entryType_f, ptr_mask, 0x7);
            SetDsNeoLpmIpv6Bit128Snake(V, entry_0_nexthop_f + step*(entry_idx&0x1), ptr_mask, 0x3FFFF);

            break;
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:
            p_hw_ipaddr = p_l0_info->ip;
            step = DsNeoLpmIpv4Bit32SnakeExt_entry_1_ipAddr_f - DsNeoLpmIpv4Bit32SnakeExt_entry_0_ipAddr_f;

            if (!is_update)
            {
                /* 1. data */
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_ipAddr_f + step*entry_idx, ptr, *p_hw_ipaddr);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_maskLen_f + step*entry_idx, ptr, masklen);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_bucketSel_f + step*entry_idx, ptr, bucketSel);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nextBucketSel_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sub_bkt : 0);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_snakePoint_f + step*entry_idx, ptr, p_l0_info->p_l0_item ? p_l0_info->p_l0_item->sram_idx : 0);

                /* 2. mask */
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_ipAddr_f + step*entry_idx, ptr_mask, 0xFFFFFFFF);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_maskLen_f + step*entry_idx, ptr_mask, 0x3F);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_bucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nextBucketSel_f + step*entry_idx, ptr_mask, 0x3);
                SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_snakePoint_f + step*entry_idx, ptr_mask, 0xFFFF);
            }

            /* 1. data */
            SetDsNeoLpmIpv4Bit32SnakeExt(V, entryType_f, ptr, type);
            SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nexthop_f + step*entry_idx, ptr, ad_index);

            /* 2. mask */
            SetDsNeoLpmIpv4Bit32SnakeExt(V, entryType_f, ptr_mask, 0x7);
            SetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nexthop_f + step*entry_idx, ptr_mask, 0x3FFFF);

            break;
       default:
            break;
    }

    if (!p_data)
    {
        #if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
        DO_SLAVE_LOOP_END
        if (g_sys_nalpm2_master[lchip]->ipsa_enable)
        {
            cmd = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
            DO_SLAVE_LOOP_END
        }
        #else
        tbl_entry_t tbl_entry;

        tbl_entry.data_entry = (uint32*)ptr;
        tbl_entry.mask_entry = (uint32*)ptr_mask;

        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry));
        DO_SLAVE_LOOP_END

        if (g_sys_nalpm2_master[lchip]->ipsa_enable)
        {
            cmd = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry));
            DO_SLAVE_LOOP_END
        }
        #endif
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nalpm: write %s[%d],entry_idx[%d]\n", DRV_TABLE_NAME(lchip, tbl_id), hw_idx, entry_idx);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_write_sram_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint8 snake_idx, uint8 entry_idx, uint8 is_update, void* p_data, void* p_data_mask)
{
    sys_nalpm2_sram_entry_type_t type = p_l0_item->sram_type;
    uint32 DsNeoLpmMemorySnake[12] = {0};
    uint32 DsNeoLpmMemorySnake_mask[12] = {0};
    void *ptr = DsNeoLpmMemorySnake;
    void* ptr_mask = DsNeoLpmMemorySnake_mask;
    uint32 tbl_id = 0, tbl_id1 = 0;
    uint32 hw_idx = 0;
    uint32 cmd = 0;
    uint8 loop_lchip = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);


    ptr = (p_data) ? p_data : DsNeoLpmMemorySnake;
    ptr_mask = (p_data_mask) ? p_data_mask : DsNeoLpmMemorySnake_mask;

    if (!p_data)
    {
        _sys_nalpm2_get_table_id_l1(lchip, type, snake_idx, &tbl_id, &tbl_id1);
        hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item->sram_idx, snake_idx);
        #if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
        #endif
    }

    if(g_sys_nalpm2_master[lchip]->build_l1_snake_cb[type])
    {
        g_sys_nalpm2_master[lchip]->build_l1_snake_cb[type](p_l0_item, p_l1_info, entry_idx, is_update, ptr, ptr_mask);
    }

    if (!p_data)
    {
        #if (1 == SDK_WORK_PLATFORM)
        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
        DO_SLAVE_LOOP_END
        
        if (g_sys_nalpm2_master[lchip]->ipsa_enable)
        {
            cmd = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), ptr));
            DO_SLAVE_LOOP_END
        }
        #else
        tbl_entry_t tbl_entry;

        tbl_entry.data_entry = (uint32*)ptr;
        tbl_entry.mask_entry = (uint32*)ptr_mask;

        cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
        DO_SLAVE_LOOP_START
        CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry));
        DO_SLAVE_LOOP_END

        if (g_sys_nalpm2_master[lchip]->ipsa_enable)
        {
            cmd = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            CTC_ERROR_RETURN(DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry));
            DO_SLAVE_LOOP_END
        }
        #endif

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "nalpm: write %s[%d],entry_idx[%d]\n", DRV_TABLE_NAME(lchip, tbl_id), hw_idx, entry_idx);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_decode_sram_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_info_t* p_l0_info, uint8 entry_idx, void* ptr)
{
    uint8 step = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    switch (p_tcam_item->sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V6_64:
        {
            ipv6_addr_t ipv6_tmp;
            sal_memset(&ipv6_tmp, 0, sizeof(ipv6_addr_t));

            step = DsNeoLpmIpv6Bit64Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit64Snake_entry_0_ipAddr_f;

            GetDsNeoLpmIpv6Bit64Snake(A, entry_0_ipAddr_f + step*(entry_idx%3), ptr, &ipv6_tmp);
            p_l0_info->ip[2] = ipv6_tmp[0];
            p_l0_info->ip[3] = ipv6_tmp[1];
            p_l0_info->route_masklen = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_maskLen_f + step*(entry_idx%3), ptr);
            p_l0_info->ad_idx = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_nexthop_f + step*(entry_idx % 3), ptr);

            p_l0_info->p_l0_item->sub_bkt = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr);
            p_l0_info->p_l0_item->sram_idx = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr);


            break;
        }
        case SYS_NALPM2_SRAM_TYPE_V6_128:

            step = DsNeoLpmIpv6Bit128Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit128Snake_entry_0_ipAddr_f;

            GetDsNeoLpmIpv6Bit128Snake(A, entry_0_ipAddr_f+ step*(entry_idx&0x1), ptr, p_l0_info->ip);
            p_l0_info->ad_idx = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_nexthop_f + step*(entry_idx&0x1), ptr);
            p_l0_info->route_masklen = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_maskLen_f+ step*(entry_idx&0x1), ptr);

            p_l0_info->p_l0_item->sub_bkt = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_nextBucketSel_f + step*entry_idx, ptr);
            p_l0_info->p_l0_item->sram_idx = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_snakePoint_f + step*entry_idx, ptr);

            break;
        case SYS_NALPM2_SRAM_TYPE_V4_EXT:

            step = DsNeoLpmIpv4Bit32SnakeExt_entry_1_ipAddr_f - DsNeoLpmIpv4Bit32SnakeExt_entry_0_ipAddr_f;

            p_l0_info->ip[0] = GetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_ipAddr_f + step*entry_idx, ptr);
            p_l0_info->route_masklen = GetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_maskLen_f + step*entry_idx, ptr);

            p_l0_info->ad_idx = GetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nexthop_f + step*entry_idx, ptr);
            p_l0_info->p_l0_item->sub_bkt = GetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_nextBucketSel_f + step*entry_idx, ptr);
            p_l0_info->p_l0_item->sram_idx = GetDsNeoLpmIpv4Bit32SnakeExt(V, entry_0_snakePoint_f + step*entry_idx, ptr);

            break;
       default:
            break;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_decode_sram_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint8 entry_idx, void* ptr)
{
    uint8 step = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    switch (p_l0_item->sram_type)
    {
        case SYS_NALPM2_SRAM_TYPE_V4_32:

            step = DsNeoLpmIpv4Bit32Snake_entry_1_ipAddr_f - DsNeoLpmIpv4Bit32Snake_entry_0_ipAddr_f;

            p_l0_item->sub_bkt = GetDsNeoLpmIpv4Bit32Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr);

            p_l1_info->ip.ipv4 = GetDsNeoLpmIpv4Bit32Snake(V, entry_0_ipAddr_f + step*entry_idx, ptr);
            p_l1_info->masklen = GetDsNeoLpmIpv4Bit32Snake(V, entry_0_maskLen_f + step*entry_idx, ptr);

            break;
        case SYS_NALPM2_SRAM_TYPE_V6_64:
        {
            ipv6_addr_t ipv6_tmp;
            sal_memset(&ipv6_tmp, 0, sizeof(ipv6_addr_t));

            step = DsNeoLpmIpv6Bit64Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit64Snake_entry_0_ipAddr_f;

            p_l0_item->sub_bkt = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_bucketSel_f + step*entry_idx, ptr);

            GetDsNeoLpmIpv6Bit64Snake(A, entry_0_ipAddr_f + step*(entry_idx%3), ptr, ipv6_tmp);
            p_l1_info->ip.ipv6[2] = ipv6_tmp[0];
            p_l1_info->ip.ipv6[3] = ipv6_tmp[1];
            p_l1_info->masklen = GetDsNeoLpmIpv6Bit64Snake(V, entry_0_maskLen_f + step*(entry_idx%3), ptr);

            break;
        }
        case SYS_NALPM2_SRAM_TYPE_V6_128:
            step = DsNeoLpmIpv6Bit128Snake_entry_1_ipAddr_f - DsNeoLpmIpv6Bit128Snake_entry_0_ipAddr_f;

            p_l0_item->sub_bkt = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_bucketSel_f + step*(entry_idx&0x1), ptr);

            GetDsNeoLpmIpv6Bit128Snake(A, entry_0_ipAddr_f+ step*(entry_idx&0x1), ptr, &(p_l1_info->ip.ipv6));
            p_l1_info->masklen = GetDsNeoLpmIpv6Bit128Snake(V, entry_0_maskLen_f+ step*(entry_idx&0x1), ptr);

            break;
       default:
            break;
    }

    return CTC_E_NONE;
}

INLINE int32
_sys_nalpm2_set_sram_type_l0(uint8 lchip, uint8 ip_ver, uint8 router_mask_len, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    if (ip_ver == CTC_IP_VER_6)
    {
        if (router_mask_len <= 64 && g_sys_nalpm2_master[lchip]->use_snake64)
        {
            p_tcam_item->sram_type = SYS_NALPM2_SRAM_TYPE_V6_64;
        }
        else
        {
            p_tcam_item->sram_type = SYS_NALPM2_SRAM_TYPE_V6_128;
        }
    }
    else
    {
        p_tcam_item->sram_type = SYS_NALPM2_SRAM_TYPE_V4_EXT;
    }

    return CTC_E_NONE;
}

INLINE int32
_sys_nalpm2_set_sram_type_l1(uint8 lchip, uint8 ip_ver, uint8 router_mask_len, sys_nalpm2_l0_item_t* p_l0_item)
{
    if (ip_ver == CTC_IP_VER_6)
    {
        if (router_mask_len <= 64 && g_sys_nalpm2_master[lchip]->use_snake64)
        {
            p_l0_item->sram_type = SYS_NALPM2_SRAM_TYPE_V6_64;
        }
        else
        {
            p_l0_item->sram_type = SYS_NALPM2_SRAM_TYPE_V6_128;
        }
    }
    else
    {
        p_l0_item->sram_type = SYS_NALPM2_SRAM_TYPE_V4_32;
    }

    return CTC_E_NONE;
}

void
_sys_nalpm2_build_snake_ipv4_32_l1(sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_mask)
{
    sys_ds_l1ipv4_snake_at_t* p_v4_snake_data = NULL;
    sys_ds_l1ipv4_snake_at_t* p_v4_snake_mask = NULL;

    p_v4_snake_data = (sys_ds_l1ipv4_snake_at_t*)p_ds_data;
    p_v4_snake_mask = (sys_ds_l1ipv4_snake_at_t*)p_ds_mask;

    p_v4_snake_data->entry_type = p_l0_item->sram_type;
    p_v4_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v4_snake_data->entry0_ipaddr_0_28   = (p_l1_info->ip.ipv4) & 0x1fffffff;
                p_v4_snake_data->entry0_ipaddr_29_31  = ((p_l1_info->ip.ipv4) >> 29) & 0x7;
                p_v4_snake_mask->entry0_ipaddr_0_28   = 0x1fffffff;
                p_v4_snake_mask->entry0_ipaddr_29_31  = 0x7;

                p_v4_snake_data->entry0_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry0_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry0_bucketsel_0_1 =  p_l0_item->sub_bkt;
                p_v4_snake_mask->entry0_bucketsel_0_1 = 0x3;
            }
            p_v4_snake_data->entry0_nexthop_0_17  = p_l1_info->ad_index;
            p_v4_snake_mask->entry0_nexthop_0_17  = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v4_snake_data->entry1_ipaddr_0_2    = (p_l1_info->ip.ipv4) & 0x7;
                p_v4_snake_data->entry1_ipaddr_3_26   = ((p_l1_info->ip.ipv4) >> 3) & 0xffffff;
                p_v4_snake_data->entry1_ipaddr_27_31  = ((p_l1_info->ip.ipv4) >> 27) & 0x1f;
                p_v4_snake_mask->entry1_ipaddr_0_2    = 0x7;
                p_v4_snake_mask->entry1_ipaddr_3_26   = 0xffffff;
                p_v4_snake_mask->entry1_ipaddr_27_31  = 0x1f;


                p_v4_snake_data->entry1_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry1_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry1_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v4_snake_mask->entry1_bucketsel_0_1 = 0x3;
            }
            p_v4_snake_data->entry1_nexthop_0_17  = p_l1_info->ad_index;
            p_v4_snake_mask->entry1_nexthop_0_17  = 0x3ffff;
        break;
        case 2:
            if(!is_update)
            {
                p_v4_snake_data->entry2_ipaddr_0_0    = (p_l1_info->ip.ipv4) & 0x1;
                p_v4_snake_data->entry2_ipaddr_1_31   = ((p_l1_info->ip.ipv4) >> 1) & 0x7fffffff;
                p_v4_snake_mask->entry2_ipaddr_0_0    = 0x1;
                p_v4_snake_mask->entry2_ipaddr_1_31   = 0x7fffffff;

                p_v4_snake_data->entry2_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry2_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry2_bucketsel_0_0 = (p_l0_item->sub_bkt) & 0x1;
                p_v4_snake_data->entry2_bucketsel_1_1 = ((p_l0_item->sub_bkt) >> 1) & 0x1;
                p_v4_snake_mask->entry2_bucketsel_0_0 = 0x1;
                p_v4_snake_mask->entry2_bucketsel_1_1 = 0x1;
            }
            p_v4_snake_data->entry2_nexthop_0_0   = (p_l1_info->ad_index) & 0x1;
            p_v4_snake_data->entry2_nexthop_1_17  = ((p_l1_info->ad_index) >> 1) & 0x1ffff;
            p_v4_snake_mask->entry2_nexthop_0_0   = 0x1;
            p_v4_snake_mask->entry2_nexthop_1_17  = 0x1ffff;
        break;
        case 3:
            if(!is_update)
            {
                p_v4_snake_data->entry3_ipaddr_0_30   = (p_l1_info->ip.ipv4) & 0x7fffffff;
                p_v4_snake_data->entry3_ipaddr_31_31  = ((p_l1_info->ip.ipv4) >> 31) & 0x1;
                p_v4_snake_mask->entry3_ipaddr_0_30   = 0x7fffffff;
                p_v4_snake_mask->entry3_ipaddr_31_31  = 0x1;

                p_v4_snake_data->entry3_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry3_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry3_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v4_snake_mask->entry3_bucketsel_0_1 = 0x3;
            }
            p_v4_snake_data->entry3_nexthop_0_17  = p_l1_info->ad_index;
            p_v4_snake_mask->entry3_nexthop_0_17  = 0x3ffff;
        break;
        case 4:
            if(!is_update)
            {
                p_v4_snake_data->entry4_ipaddr_0_4    = (p_l1_info->ip.ipv4) & 0x1f;
                p_v4_snake_data->entry4_ipaddr_5_28   = ((p_l1_info->ip.ipv4) >> 5) & 0xffffff;
                p_v4_snake_data->entry4_ipaddr_29_31  = ((p_l1_info->ip.ipv4) >> 29) & 0x7;
                p_v4_snake_mask->entry4_ipaddr_0_4    = 0x1f;
                p_v4_snake_mask->entry4_ipaddr_5_28   = 0xffffff;
                p_v4_snake_mask->entry4_ipaddr_29_31  = 0x7;

                p_v4_snake_data->entry4_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry4_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry4_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v4_snake_mask->entry4_bucketsel_0_1 = 0x3;
            }
            p_v4_snake_data->entry4_nexthop_0_17  = p_l1_info->ad_index;
            p_v4_snake_mask->entry4_nexthop_0_17  = 0x3ffff;
        break;
        case 5:
            if(!is_update)
            {
                p_v4_snake_data->entry5_ipaddr_0_2    = (p_l1_info->ip.ipv4) & 0x7;
                p_v4_snake_data->entry5_ipaddr_3_31   = ((p_l1_info->ip.ipv4) >> 3) & 0x1fffffff;
                p_v4_snake_mask->entry5_ipaddr_0_2    = 0x7;
                p_v4_snake_mask->entry5_ipaddr_3_31   = 0x1fffffff;

                p_v4_snake_data->entry5_masklen_0_5   = p_l1_info->masklen;
                p_v4_snake_mask->entry5_masklen_0_5   = 0x3f;

                p_v4_snake_data->entry5_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v4_snake_mask->entry5_bucketsel_0_1 = 0x3;
            }
            p_v4_snake_data->entry5_nexthop_0_2   = (p_l1_info->ad_index) & 0x7;
            p_v4_snake_data->entry5_nexthop_3_17  = ((p_l1_info->ad_index) >> 3) & 0x7fff;
            p_v4_snake_mask->entry5_nexthop_0_2   = 0x7;
            p_v4_snake_mask->entry5_nexthop_3_17  = 0x7fff;
        break;
        default:
        break;
    }
}

void
_sys_nalpm2_build_snake_ipv6_64_l1(sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_mask)
{
    sys_ds_l1ipv6_64_snake_at_t* p_v6_64_snake_data = NULL;
    sys_ds_l1ipv6_64_snake_at_t* p_v6_64_snake_mask = NULL;

    p_v6_64_snake_data = (sys_ds_l1ipv6_64_snake_at_t*)p_ds_data;
    p_v6_64_snake_mask = (sys_ds_l1ipv6_64_snake_at_t*)p_ds_mask;

    p_v6_64_snake_data->entry_type = p_l0_item->sram_type;
    p_v6_64_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v6_64_snake_data->entry0_ipaddr0_0_28   = (p_l1_info->ip.ipv6[2]) & 0x1fffffff;
                p_v6_64_snake_data->entry0_ipaddr0_29_31  = ((p_l1_info->ip.ipv6[2]) >> 29) & 0x7;
                p_v6_64_snake_mask->entry0_ipaddr0_0_28   = 0x1fffffff;
                p_v6_64_snake_mask->entry0_ipaddr0_29_31  = 0x7;

                p_v6_64_snake_data->entry0_ipaddr1_0_28   = (p_l1_info->ip.ipv6[3]) & 0x1fffffff;
                p_v6_64_snake_data->entry0_ipaddr1_29_31  = ((p_l1_info->ip.ipv6[3]) >> 29) & 0x7;
                p_v6_64_snake_mask->entry0_ipaddr1_0_28   = 0x1fffffff;
                p_v6_64_snake_mask->entry0_ipaddr1_29_31  = 0x7;

                p_v6_64_snake_data->entry0_masklen_0_2    = (p_l1_info->masklen) & 0x7;
                p_v6_64_snake_data->entry0_masklen_3_7    = ((p_l1_info->masklen) >> 3) & 0x1f;
                p_v6_64_snake_mask->entry0_masklen_0_2    = 0x7;
                p_v6_64_snake_mask->entry0_masklen_3_7    = 0x1f;


                p_v6_64_snake_data->entry0_bucketsel_0_1  = p_l0_item->sub_bkt;
                p_v6_64_snake_mask->entry0_bucketsel_0_1  = 0x3;
            }

            p_v6_64_snake_data->entry0_nexthop_0_17 = p_l1_info->ad_index;
            p_v6_64_snake_mask->entry0_nexthop_0_17 = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_64_snake_data->entry1_ipaddr0_0_6    = (p_l1_info->ip.ipv6[2]) & 0x7f;
                p_v6_64_snake_data->entry1_ipaddr0_7_31   = ((p_l1_info->ip.ipv6[2]) >> 7) & 0x1ffffff;
                p_v6_64_snake_mask->entry1_ipaddr0_0_6    = 0x7f;
                p_v6_64_snake_mask->entry1_ipaddr0_7_31   = 0x1ffffff;

                p_v6_64_snake_data->entry1_ipaddr1_0_6    = (p_l1_info->ip.ipv6[3]) & 0x7f;
                p_v6_64_snake_data->entry1_ipaddr1_7_30   = ((p_l1_info->ip.ipv6[3]) >> 7) & 0xffffff;
                p_v6_64_snake_data->entry1_ipaddr1_31_31  = ((p_l1_info->ip.ipv6[3]) >> 31) & 0x1;
                p_v6_64_snake_mask->entry1_ipaddr1_0_6    = 0x7f;
                p_v6_64_snake_mask->entry1_ipaddr1_7_30   = 0xffffff;
                p_v6_64_snake_mask->entry1_ipaddr1_31_31  = 0x1;

                p_v6_64_snake_data->entry1_masklen_0_7    = p_l1_info->masklen;
                p_v6_64_snake_mask->entry1_masklen_0_7    = 0xff;

                p_v6_64_snake_data->entry1_bucketsel_0_1  = p_l0_item->sub_bkt;
                p_v6_64_snake_mask->entry1_bucketsel_0_1  = 0x3;
            }
            p_v6_64_snake_data->entry1_nexthop_0_17 = p_l1_info->ad_index;
            p_v6_64_snake_mask->entry1_nexthop_0_17 = 0x3ffff;
        break;
        case 2:
            if(!is_update)
            {
                p_v6_64_snake_data->entry2_ipaddr0_0_16   = (p_l1_info->ip.ipv6[2]) & 0x1ffff;
                p_v6_64_snake_data->entry2_ipaddr0_17_31  = ((p_l1_info->ip.ipv6[2]) >> 17) & 0x7fff;
                p_v6_64_snake_mask->entry2_ipaddr0_0_16   = 0x1ffff;
                p_v6_64_snake_mask->entry2_ipaddr0_17_31  = 0x7fff;

                p_v6_64_snake_data->entry2_ipaddr1_0_8    = (p_l1_info->ip.ipv6[3]) & 0x1ff;
                p_v6_64_snake_data->entry2_ipaddr1_9_31   = ((p_l1_info->ip.ipv6[3]) >> 9) & 0x7fffff;
                p_v6_64_snake_mask->entry2_ipaddr1_0_8    = 0x1ff;
                p_v6_64_snake_mask->entry2_ipaddr1_9_31   = 0x7fffff;


                p_v6_64_snake_data->entry2_masklen_0_7    = p_l1_info->masklen;
                p_v6_64_snake_mask->entry2_masklen_0_7    = 0xff;

                p_v6_64_snake_data->entry2_bucketsel_0_1  = p_l0_item->sub_bkt;
                p_v6_64_snake_mask->entry2_bucketsel_0_1  = 0x3;
            }
            p_v6_64_snake_data->entry2_nexthop_0_8  = (p_l1_info->ad_index) & 0x1ff;
            p_v6_64_snake_data->entry2_nexthop_9_17 = ((p_l1_info->ad_index) >> 9) & 0x1ff;
            p_v6_64_snake_mask->entry2_nexthop_0_8  = 0x1ff;
            p_v6_64_snake_mask->entry2_nexthop_9_17 = 0x1ff;
        break;
        default:
        break;
    }
}

void
_sys_nalpm2_build_snake_ipv6_128_l1(sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint8 entry_idx, uint8 is_update, void* p_ds_data, void* p_ds_mask)
{
    sys_ds_l1ipv6_128_snake_at_t* p_v6_128_snake_data = NULL;
    sys_ds_l1ipv6_128_snake_at_t* p_v6_128_snake_mask = NULL;

    p_v6_128_snake_data = (sys_ds_l1ipv6_128_snake_at_t*)p_ds_data;
    p_v6_128_snake_mask = (sys_ds_l1ipv6_128_snake_at_t*)p_ds_mask;

    p_v6_128_snake_data->entry_type = p_l0_item->sram_type;
    p_v6_128_snake_mask->entry_type = 0x7;
    switch (entry_idx)
    {
        case 0:
            if(!is_update)
            {
                p_v6_128_snake_data->entry0_ipaddr0_0_28  = (p_l1_info->ip.ipv6[0]) & 0x1fffffff;
                p_v6_128_snake_data->entry0_ipaddr0_29_31 = ((p_l1_info->ip.ipv6[0]) >> 29) & 0x7;
                p_v6_128_snake_mask->entry0_ipaddr0_0_28  = 0x1fffffff;
                p_v6_128_snake_mask->entry0_ipaddr0_29_31 = 0x7;

                p_v6_128_snake_data->entry0_ipaddr1_0_28  = (p_l1_info->ip.ipv6[1]) & 0x1fffffff;
                p_v6_128_snake_data->entry0_ipaddr1_29_31 = ((p_l1_info->ip.ipv6[1]) >> 29) & 0x7;
                p_v6_128_snake_mask->entry0_ipaddr1_0_28  = 0x1fffffff;
                p_v6_128_snake_mask->entry0_ipaddr1_29_31 = 0x7;

                p_v6_128_snake_data->entry0_ipaddr2_0_20  = (p_l1_info->ip.ipv6[2]) & 0x1fffff;
                p_v6_128_snake_data->entry0_ipaddr2_21_31 = ((p_l1_info->ip.ipv6[2]) >> 21) & 0x7ff;
                p_v6_128_snake_mask->entry0_ipaddr2_0_20  = 0x1fffff;
                p_v6_128_snake_mask->entry0_ipaddr2_21_31 = 0x7ff;

                p_v6_128_snake_data->entry0_ipaddr3_0_20  = (p_l1_info->ip.ipv6[3]) & 0x1fffff;
                p_v6_128_snake_data->entry0_ipaddr3_21_31 = ((p_l1_info->ip.ipv6[3]) >> 21) & 0x7ff;
                p_v6_128_snake_mask->entry0_ipaddr3_0_20  = 0x1fffff;
                p_v6_128_snake_mask->entry0_ipaddr3_21_31 = 0x7ff;

                p_v6_128_snake_data->entry0_masklen_0_2   = (p_l1_info->masklen) & 0x7;
                p_v6_128_snake_data->entry0_masklen_3_7   = ((p_l1_info->masklen) >> 3) & 0x1f;
                p_v6_128_snake_mask->entry0_masklen_0_2   = 0x7;
                p_v6_128_snake_mask->entry0_masklen_3_7   = 0x1f;

                p_v6_128_snake_data->entry0_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v6_128_snake_mask->entry0_bucketsel_0_1 = 0x03;
            }
            p_v6_128_snake_data->entry0_nexthop_0_17 = p_l1_info->ad_index;
            p_v6_128_snake_mask->entry0_nexthop_0_17 = 0x3ffff;
        break;
        case 1:
            if(!is_update)
            {
                p_v6_128_snake_data->entry1_ipaddr0_0_30  = (p_l1_info->ip.ipv6[0]) & 0x7fffffff;
                p_v6_128_snake_data->entry1_ipaddr0_31_31 = ((p_l1_info->ip.ipv6[0]) >> 31) & 0x1;
                p_v6_128_snake_mask->entry1_ipaddr0_0_30  = 0x7fffffff;
                p_v6_128_snake_mask->entry1_ipaddr0_31_31 = 0x1;

                p_v6_128_snake_data->entry1_ipaddr1_0_30  = (p_l1_info->ip.ipv6[1]) & 0x7fffffff;
                p_v6_128_snake_data->entry1_ipaddr1_31_31 = ((p_l1_info->ip.ipv6[1]) >> 31) & 0x1;
                p_v6_128_snake_mask->entry1_ipaddr1_0_30  = 0x7fffffff;
                p_v6_128_snake_mask->entry1_ipaddr1_31_31 = 0x1;

                p_v6_128_snake_data->entry1_ipaddr2_0_22  = (p_l1_info->ip.ipv6[2]) & 0x7fffff;
                p_v6_128_snake_data->entry1_ipaddr2_23_31 = ((p_l1_info->ip.ipv6[2]) >> 23) & 0x1ff;
                p_v6_128_snake_mask->entry1_ipaddr2_0_22  = 0x7fffff;
                p_v6_128_snake_mask->entry1_ipaddr2_23_31 = 0x1ff;

                p_v6_128_snake_data->entry1_ipaddr3_0_22  = (p_l1_info->ip.ipv6[3]) & 0x7fffff;
                p_v6_128_snake_data->entry1_ipaddr3_23_31 = ((p_l1_info->ip.ipv6[3]) >> 23) & 0x1ff;
                p_v6_128_snake_mask->entry1_ipaddr3_0_22  = 0x7fffff;
                p_v6_128_snake_mask->entry1_ipaddr3_23_31 = 0x1ff;

                p_v6_128_snake_data->entry1_masklen_0_4   = (p_l1_info->masklen) & 0x1f;
                p_v6_128_snake_data->entry1_masklen_5_7   = ((p_l1_info->masklen) >> 5) & 0x7;
                p_v6_128_snake_mask->entry1_masklen_0_4   = 0x1f;
                p_v6_128_snake_mask->entry1_masklen_5_7   = 0x7;

                p_v6_128_snake_data->entry1_bucketsel_0_1 = p_l0_item->sub_bkt;
                p_v6_128_snake_mask->entry1_bucketsel_0_1 = 0x03;
            }
            p_v6_128_snake_data->entry1_nexthop_0_17 = p_l1_info->ad_index;
            p_v6_128_snake_mask->entry1_nexthop_0_17 = 0x3ffff;
        break;
        default:
        break;
    }
}

#define ______RCover______

int32
_sys_nalpm2_update_longer_pfx_AD_add(trie_node_t* p_longer_pfx_node,void* data)
{
    sys_nalpm2_route_and_lchip_t* route_and_lchip = (sys_nalpm2_route_and_lchip_t*)data;
    sys_ipuc_info_t* p_new_route = route_and_lchip->p_l1_info;
    sys_nalpm2_trie_tcam_item_t * p_trie_tcam_item = NULL;
    int32 ret = CTC_E_NONE;
    uint32 hw_idx = 0;
    uint32 ad_idx = 0;
    uint8 lchip = route_and_lchip->lchip;
    uint8 masklen0 = 0;
    uint8 masklen1 = 0;
    uint8 timer = 0;
    uint8 hit = 0;

    /* 0. prepare data */
    p_trie_tcam_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_tcam_item_t, node);
    masklen0 = p_new_route->masklen;
    masklen1 = p_trie_tcam_item->tcam_item.p_l0_root_AD ? p_trie_tcam_item->tcam_item.p_l0_root_AD->masklen : 0;
    ad_idx = p_new_route->ad_index;

    /* 1. write tcam or set/get TCAM aging bit */
    if(route_and_lchip->ageing_opt == IPUC_LPM_AGING_NONE)
    {
        if (p_trie_tcam_item->tcam_item.p_l0_root_AD == NULL || masklen1 <= masklen0)
        {
            p_trie_tcam_item->tcam_item.p_l0_root_AD = p_new_route;
            CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, &(p_trie_tcam_item->tcam_item), DO_UPDATE, ad_idx));
        }
    }
    else if(p_new_route == p_trie_tcam_item->tcam_item.p_l0_root_AD)
    {
        route_and_lchip->is_covered = 1;
        hw_idx = p_trie_tcam_item->tcam_item.tcam_idx;

        if(route_and_lchip->ageing_opt == IPUC_LPM_AGING_GET)
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_status(lchip, SYS_AGING_DOMAIN_TCAM, hw_idx, &hit));
            route_and_lchip->ageing_bit = (hit == 1) ? 1 : route_and_lchip->ageing_bit;
        }
        else
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_timer(lchip, SYS_AGING_DOMAIN_TCAM, hw_idx, &timer));
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->set_aging_status(lchip, SYS_AGING_DOMAIN_TCAM, hw_idx, timer, route_and_lchip->ageing_bit));
        }
    }

    return ret;
}

int32
_sys_nalpm2_update_lvl0_longer_pfx_AD_add(trie_node_t* p_longer_pfx_node, void* data)
{

    sys_nalpm2_route_and_lchip_t* route_and_lchip = (sys_nalpm2_route_and_lchip_t*) data;
    sys_ipuc_info_t* p_new_route = route_and_lchip->p_l1_info;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_info_t* p_route_info = NULL;
    int32 ret = CTC_E_NONE;
    uint8 hit = 0;
    uint8 lchip = route_and_lchip->lchip;

    /* 0. prepare data */
    p_trie_l0_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_l0_item_t, node);
    p_l0_item = &p_trie_l0_item->l0_item;

    if (route_and_lchip->p_father == p_longer_pfx_node)
    {
        return 0;
    }

    /* 1. write sram */
    if(route_and_lchip->ageing_opt == IPUC_LPM_AGING_NONE)
    {
        if (p_l0_item->p_l1_root_AD == NULL
            || p_l0_item->p_l1_root_AD->masklen <= p_new_route->masklen)
        {
            p_l0_item->p_l1_root_AD = p_new_route;
            p_tcam_item = p_l0_item->p_tcam_item;
            p_route_info = p_l0_item->p_l1_root_info;
            p_route_info->ad_idx = p_new_route->ad_index;

            _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_route_info, p_route_info->hw_position[0], p_route_info->hw_position[1], 1, NULL, NULL);
        }
    }
    else if(p_new_route == p_trie_l0_item->l0_item.p_l1_root_AD)
    {
        uint32 hw_idx = 0;
        uint8 domain_type = 0;
        uint8 timer = 0;

        route_and_lchip->is_covered = 1;

        hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_trie_l0_item->l0_item.p_tcam_item->sram_idx, p_trie_l0_item->l0_item.p_l1_root_info->hw_position[0]);

        domain_type = p_trie_l0_item->l0_item.p_l1_root_info->hw_position[0] >= NALPM2_BUKCET_SNACK_PER_GRP_L1(lchip) ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 : SYS_AGING_DOMAIN_LPM_HASH_GROUP0;

        if (route_and_lchip->ageing_opt == IPUC_LPM_AGING_GET)/*get*/
        {
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC) ? CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT) : domain_type;
            ret = MCHIP_LA(lchip)->get_aging_status(lchip, domain_type, ((LEVEL0 << 30) | (p_trie_l0_item->l0_item.p_l1_root_info->hw_position[1] << 24) | hw_idx), &hit);
            route_and_lchip->ageing_bit = (hit == 1) ? 1 : route_and_lchip->ageing_bit;
        }
        else
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_timer(lchip, domain_type, ((LEVEL0 << 30) | (p_trie_l0_item->l0_item.p_l1_root_info->hw_position[1] << 24) | hw_idx), &timer));
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            ret = MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, ((LEVEL0 << 30) | (p_trie_l0_item->l0_item.p_l1_root_info->hw_position[1] << 24) | hw_idx), timer, route_and_lchip->ageing_bit);
        }
    }

    return ret;
}

int32
_sys_nalpm2_add_route_cover(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint32 nh_id,
                                   uint32 total_skip_len, uint8 ageing_opt, uint8 *p_hit)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = CONTAINER_OF(p_l0_item, sys_nalpm2_trie_l0_item_t, l0_item);
    trie_node_t* p_prefix_node = &(p_trie_l0_item->node);
    sys_nalpm2_route_and_lchip_t route_and_lchip;
    uint32 *ip = NULL;
    uint32 key[4] = {0};
    uint8 hw_position[2] = {0};
    int32 ret = CTC_E_NONE;
    uint8 length = 0;
    uint8 ip_ver = 0;
    uint16 vrf_id = 0;

    /* 0. prepare data */
    ip_ver = SYS_IPUC_VER(p_l1_info);
    length = p_l1_info->masklen;
    vrf_id = p_l1_info->vrf_id;
    hw_position[0] = p_l1_info->snake_idx;
    hw_position[1] = p_l1_info->entry_offset;
    ip = &(p_l1_info->ip.ipv4);
    sal_memcpy(key, ip, (IP_ADDR_SIZE(ip_ver)));
    SYS_IPV6_IP_SORT(ip_ver, key);
    SYS_NALPM_CONVERT_TO_LSB(key, length, ip_ver);

    sal_memset(&route_and_lchip, 0, sizeof(route_and_lchip));
    route_and_lchip.prefix_len = total_skip_len;
    route_and_lchip.p_father = p_prefix_node;
    route_and_lchip.ageing_opt = ageing_opt;
    route_and_lchip.p_l1_info = p_l1_info;
    route_and_lchip.origin_lchip = lchip;
    route_and_lchip.lchip = lchip;
    route_and_lchip.nh_id = nh_id;

    /* 0.1 whether aging option is SET */
    if(ageing_opt == IPUC_LPM_AGING_SET)
    {
        route_and_lchip.ageing_bit = *p_hit;
    }

    /* 1. update router cover */
    if (ip_ver == 0)
    {
        /* 1.1 propagate the L0 sram */
        ret = sys_nalpm_trie_propagate_prefix(p_prefix_node,
                                              key, length + p_prefix_node->skip_len - total_skip_len,
                                              _sys_nalpm2_update_lvl0_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);

        /* 1.2 propagate the TCAM */
        ret = sys_nalpm_trie_propagate_prefix(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie,
                                              key, length,
                                              _sys_nalpm2_update_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);
    }
    else
    {
        /* 1.1 propagate the L0 sram */
        ret = sys_nalpm_v6_trie_propagate_prefix(p_prefix_node,
                                              key, length + p_prefix_node->skip_len - total_skip_len,
                                              _sys_nalpm2_update_lvl0_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);

        /* 1.2 propagate the TCAM */
        ret = sys_nalpm_v6_trie_propagate_prefix(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie,
                                              key, length,
                                              _sys_nalpm2_update_longer_pfx_AD_add,
                                              (void *)&route_and_lchip, 1);

    }

    /* 2. set/get L1 SRAM aging bit */
    if (IPUC_LPM_AGING_NONE == route_and_lchip.ageing_opt)
    {
        return ret;
    }
    if (route_and_lchip.is_covered == 1)
    {
        if (route_and_lchip.ageing_opt == IPUC_LPM_AGING_GET)
        {
            *p_hit = route_and_lchip.ageing_bit;
        }
    }
    else
    {
        uint32 hw_idx = 0;
        uint8 domain_type = 0;
        uint8 timer = 0;

        hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item->sram_idx, hw_position[0]);
        domain_type = hw_position[0] >= NALPM2_BUKCET_SNACK_PER_GRP_L1(lchip) ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 : SYS_AGING_DOMAIN_LPM_HASH_GROUP0;

        if (route_and_lchip.ageing_opt == IPUC_LPM_AGING_GET)/*get*/
        {
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            ret = MCHIP_LA(lchip)->get_aging_status(lchip, domain_type, ((LEVEL1 << 30) | (hw_position[1] << 24) | hw_idx), p_hit);
        }
        else
        {
            CTC_ERROR_RETURN(MCHIP_LA(lchip)->get_aging_timer(lchip, domain_type, ((LEVEL1 << 30) | (hw_position[1] << 24) | hw_idx), &timer));
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            ret = MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, ((LEVEL1 << 30) | (hw_position[1] << 24) | hw_idx), timer, *p_hit ? 1 : 0);
        }
    }

    return ret;
}

int32
_sys_nalpm2_update_longer_pfx_AD_del(trie_node_t* p_longer_pfx_node,void* data)
{
    sys_nalpm2_route_and_lchip_t* p_route_and_lchip = (sys_nalpm2_route_and_lchip_t*)data;
    sys_ipuc_info_t* p_l1_info = p_route_and_lchip->p_l1_info;
    trie_node_t* p_father_node = p_route_and_lchip->p_father;
    sys_nalpm2_trie_tcam_item_t * p_trie_tcam_item = NULL;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    sys_ipuc_info_t* p_best_route = NULL;
    int32 ret = CTC_E_NONE;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    uint16 vrf_id = 0;
    uint8 lchip = p_route_and_lchip->lchip;
    uint8 ip_ver = 0;

    /* 0. prepare data */
    if(p_longer_pfx_node->type  != PAYLOAD)
    {
        return ret;
    }

    if(NULL == p_father_node)
    {
        return ret;
    }

    p_trie_tcam_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_tcam_item_t, node);
    p_trie_l0_item = CONTAINER_OF(p_father_node, sys_nalpm2_trie_l0_item_t, node);

    ip_ver = SYS_IPUC_VER(p_l1_info);
    vrf_id = p_l1_info->vrf_id;

    ret = _sys_nalpm2_route_match_l1(lchip, p_trie_tcam_item->tcam_item.p_l0_root_info, p_l1_info);
    if (0 != ret)
    {
        return ret;
    }

    if(0 != _sys_nalpm2_route_cmp_l1(lchip, p_trie_tcam_item->tcam_item.p_l0_root_AD, p_l1_info))
    {
        return ret;
    }

    /* 1. search best route */
    CTC_ERROR_RETURN(_sys_nalpm2_search_best_route_in_sram_l1(lchip, &p_trie_l0_item->l0_item, p_trie_tcam_item->tcam_item.p_l0_root_info, &p_best_route));
    p_trie_tcam_item->tcam_item.p_l0_root_AD = p_best_route;

    /* 2. update tcam */
    if (p_best_route)
    {
        uint32 ad_idx = p_best_route->ad_index;

        CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, &p_trie_tcam_item->tcam_item, DO_UPDATE, ad_idx));
    }
    else
    {
        sys_nalpm2_trie_tcam_item_t * p_root_payload = NULL;
        trie_t *prefix_trie = NULL;

        prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id];
        p_root_payload = CONTAINER_OF(prefix_trie->trie, sys_nalpm2_trie_tcam_item_t, node);

        CTC_ERROR_RETURN(_sys_nalpm2_read_tcam(lchip, &p_root_payload->tcam_item, &ad_idx));
        CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, &p_trie_tcam_item->tcam_item, DO_UPDATE, ad_idx));
    }

    return ret;
}

int32
_sys_nalpm2_update_lvl0_longer_pfx_AD_del(trie_node_t* p_longer_pfx_node, void* data)
{
    sys_nalpm2_route_and_lchip_t* p_route_and_lchip = (sys_nalpm2_route_and_lchip_t*)data;
    sys_ipuc_info_t* p_l1_info = p_route_and_lchip->p_l1_info;
    trie_node_t *p_father_node = p_route_and_lchip->p_father;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item1 = NULL;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_ipuc_info_t* p_best_route = NULL;
    int32 ret = CTC_E_NONE;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET_L0;
    uint8 lchip = p_route_and_lchip->lchip;

    if(NULL == p_father_node)
    {
        return ret;
    }

    /* 0. prepare data */
    p_trie_l0_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_l0_item_t, node);
    p_trie_l0_item1 = CONTAINER_OF(p_father_node, sys_nalpm2_trie_l0_item_t, node);
    p_l0_item = &p_trie_l0_item->l0_item;

    ret = _sys_nalpm2_route_match_l1(lchip, p_l0_item->p_l1_root_info, p_l1_info);
    if (0 != ret)
    {
        return ret;
    }

    if(0 != _sys_nalpm2_route_cmp_l1(lchip, p_l0_item->p_l1_root_AD, p_l1_info))
    {
        return ret;
    }

    /* 1. search best route */
    CTC_ERROR_RETURN(_sys_nalpm2_search_best_route_in_sram_l1(lchip, &p_trie_l0_item1->l0_item, p_l0_item->p_l1_root_info, &p_best_route));

    /* 2. write sram */
    /* 2.1 prepare data */
    p_l0_item->p_l1_root_AD = p_best_route;
    p_tcam_item = p_l0_item->p_tcam_item;
    p_l1_root_info = p_l0_item->p_l1_root_info;

    if (p_best_route)
    {
         p_l1_root_info->ad_idx = p_best_route->ad_index;
    }
    else
    {
         p_l1_root_info->ad_idx = ad_idx;
    }

    /* 2.2 write sram */
    ret = _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_l1_root_info, p_l1_root_info->hw_position[0], p_l1_root_info->hw_position[1], 1, NULL, NULL);

    return ret;
}

int32
_sys_nalpm2_deletes_route_cover(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, uint32 total_skip_len)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = CONTAINER_OF(p_l0_item, sys_nalpm2_trie_l0_item_t, l0_item);
    trie_node_t* p_prefix_node = &(p_trie_l0_item->node);
    sys_nalpm2_route_and_lchip_t del_route_lchip;
    uint32 *ip = NULL;
    uint32 key[4] = {0};
    int32 ret = CTC_E_NONE;
    uint8 length = 0;
    uint8 ip_ver = 0;
    uint16 vrf_id = 0;

    /* 0. prepare data */
    ip_ver = SYS_IPUC_VER(p_l1_info);
    length = p_l1_info->masklen;
    vrf_id = p_l1_info->vrf_id;
    ip = &p_l1_info->ip.ipv4;
    sal_memcpy(key, ip, (IP_ADDR_SIZE(ip_ver)));
    SYS_IPV6_IP_SORT(ip_ver, key);
    SYS_NALPM_CONVERT_TO_LSB(key, length, ip_ver);

    del_route_lchip.prefix_len = total_skip_len;
    del_route_lchip.p_father = p_prefix_node;
    del_route_lchip.p_l1_info = p_l1_info;
    del_route_lchip.lchip = lchip;

    /* 1. update router cover */
    if (ip_ver == 0)
    {
        /* 1.1 propagate the L0 sram */
        ret = sys_nalpm_trie_propagate_prefix(p_prefix_node,
                                              key, length  + p_prefix_node->skip_len - total_skip_len,
                                              _sys_nalpm2_update_lvl0_longer_pfx_AD_del,
                                              (void *)&del_route_lchip, 1);
        /* 1.2 propagate the TCAM */
        ret = sys_nalpm_trie_propagate_prefix(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie,
                                              key, length,
                                              _sys_nalpm2_update_longer_pfx_AD_del,
                                              (void *)&del_route_lchip, 1);
    }
    else
    {
        /* 1.1 propagate the L0 sram */
        ret = sys_nalpm_v6_trie_propagate_prefix(p_prefix_node,
                                              key, length  + p_prefix_node->skip_len - total_skip_len,
                                              _sys_nalpm2_update_lvl0_longer_pfx_AD_del,
                                              (void *)&del_route_lchip, 1);
        /* 1.2 propagate the TCAM */
        ret = sys_nalpm_v6_trie_propagate_prefix(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie,
                                              key, length,
                                              _sys_nalpm2_update_longer_pfx_AD_del,
                                              (void *)&del_route_lchip, 1);
     }

    return ret;
}

int32
_sys_nalpm2_update_longer_pfx_AD_default(trie_node_t* p_longer_pfx_node, void* data)
{
    sys_nalpm2_route_and_lchip_t* p_route_and_lchip = (sys_nalpm2_route_and_lchip_t*)data;
    sys_nalpm2_trie_tcam_item_t * p_trie_tcam_item = NULL;
    uint32 ad_idx = p_route_and_lchip->p_l0_info->ad_idx;
    int32 ret = CTC_E_NONE;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_route_and_lchip->lchip;
#endif
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(p_longer_pfx_node->type != PAYLOAD)
    {
        return ret;
    }

    p_trie_tcam_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_tcam_item_t, node);

    if(p_trie_tcam_item->tcam_item.p_l0_root_info->tcam_masklen == 0 || NULL == p_trie_tcam_item->tcam_item.p_l0_root_AD)
    {
        CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(p_route_and_lchip->lchip, &(p_trie_tcam_item->tcam_item), DO_UPDATE, ad_idx));
    }

    return ret;
}

int32
_sys_nalpm2_update_lvl0_longer_pfx_AD_default(trie_node_t* p_longer_pfx_node,void* data)
{
    sys_nalpm2_route_and_lchip_t* p_route_and_lchip = (sys_nalpm2_route_and_lchip_t*)data;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    uint32 ad_idx = p_route_and_lchip->p_l1_info->ad_index;
    int32 ret = CTC_E_NONE;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_route_and_lchip->lchip;
#endif
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(p_longer_pfx_node->type != PAYLOAD)
    {
        return ret;
    }

    p_trie_l0_item = CONTAINER_OF(p_longer_pfx_node, sys_nalpm2_trie_l0_item_t, node);
    p_l0_item = &p_trie_l0_item->l0_item;

    if (NULL == p_l0_item->p_l1_root_AD)
    {
        p_tcam_item = p_l0_item->p_tcam_item;
        p_l1_root_info = p_l0_item->p_l1_root_info;
        p_l1_root_info->ad_idx = ad_idx;
        _sys_nalpm2_write_sram_l0(p_route_and_lchip->lchip, p_tcam_item, p_l1_root_info, p_l1_root_info->hw_position[0], p_l1_root_info->hw_position[1], 1, NULL, NULL);
    }

    return ret;
}

int32
_sys_nalpm2_default_route_cover(uint8 lchip,uint8 ip_ver, uint16 vrf_id, uint32 ad_index)
{
    sys_nalpm2_route_and_lchip_t default_info;
    trie_node_t* p_prefix_node = NULL;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    default_info.p_l0_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == default_info.p_l0_info)
    {
        return CTC_E_NO_MEMORY;
    }

    default_info.lchip = lchip;
    default_info.p_l0_info->ad_idx = ad_index;
    default_info.p_l0_info->ip_ver = ip_ver;
    default_info.p_l0_info->vrf_id = vrf_id;

    p_prefix_node = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie;

    if(p_prefix_node->child[0].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse(p_prefix_node->child[0].child_node, _sys_nalpm2_update_longer_pfx_AD_default, (void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret, error_proc);
    }

    if(p_prefix_node->child[1].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse(p_prefix_node->child[1].child_node, _sys_nalpm2_update_longer_pfx_AD_default, (void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret, error_proc);
    }

error_proc:
    mem_free(default_info.p_l0_info);

    return ret;
}

int32
_sys_nalpm2_default_lvl0_route_cover(uint8 lchip,uint8 ip_ver, uint16 vrf_id, uint32 ad_index)
{
    sys_nalpm2_route_and_lchip_t default_info;
    trie_node_t* p_prefix_node = NULL;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    default_info.p_l1_info = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_ipuc_info_t));
    if(NULL == default_info.p_l1_info)
    {
        return CTC_E_NO_MEMORY;
    }

    default_info.lchip = lchip;
    default_info.p_l1_info->ad_index = ad_index;
    default_info.p_l1_info->route_flag |= (ip_ver == CTC_IP_VER_6) ? SYS_IPUC_FLAG_IS_IPV6 : 0;
    default_info.p_l1_info->vrf_id = vrf_id;

    p_prefix_node = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]->trie;

    if(p_prefix_node->child[0].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse (p_prefix_node->child[0].child_node, _sys_nalpm2_update_lvl0_longer_pfx_AD_default,(void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret,error_proc);
    }

    if(p_prefix_node->child[1].child_node)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_traverse (p_prefix_node->child[1].child_node, _sys_nalpm2_update_lvl0_longer_pfx_AD_default,(void *)&default_info, _TRIE_PREORDER_TRAVERSE), ret,error_proc);
    }

error_proc:
    mem_free(default_info.p_l1_info);

    return ret;
}

#define ______Bucket______

int32
_sys_nalpm2_bucket_init_l0(uint8 lchip)
{
    sys_usw_opf_t opf;
    uint32 entry_num = 0;
    uint32 max_size = 0;
    uint16 i = 0;

    /* 1. get table entry num */
    CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmL0Ipv4Bit32Snake_t, &entry_num));

    /* 2. prepare data */
    NALPM2_BUCKET_L0(lchip).bkt_depth = 8*1024;
    NALPM2_BUCKET_L0(lchip).snake_group_num = g_sys_nalpm2_master[lchip]->ipsa_enable ? 1 : 2;
    NALPM2_BUCKET_L0(lchip).snake_per_group = (entry_num / NALPM2_BUCKET_L0(lchip).bkt_depth);
    if(!NALPM2_BUCKET_L0(lchip).snake_per_group)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "LPM L0 sram not enough!!!");
        return CTC_E_NO_RESOURCE;
    }
    NALPM2_BUCKET_L0(lchip).real_bkt_depth = NALPM2_BUCKET_L0(lchip).bkt_depth;
    NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V4] = 4;
    NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V6_64] = 3;
    NALPM2_BUCKET_L0(lchip).snake_fmt_num[NALPM2_FMT_V6_128] = 2;
    NALPM2_BUCKET_L0(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V4_32] = DsNeoLpmL0Ipv4Bit32Snake_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V6_64] = DsNeoLpmL0Ipv6Bit64Snake_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V6_128] = DsNeoLpmL0Ipv6Bit128Snake_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V4_EXT] = DsNeoLpmIpv4Bit32SnakeExt_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V4_32] = DsNeoLpmL0Ipv4Bit32Snake1_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V6_64] = DsNeoLpmL0Ipv6Bit64Snake1_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V6_128] = DsNeoLpmL0Ipv6Bit128Snake1_t;
    NALPM2_BUCKET_L0(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V4_EXT] = DsNeoLpmIpv4Bit32SnakeExt1_t;

    max_size = NALPM2_BUCKET_L0(lchip).real_bkt_depth;

    /* 2. init sram index opf */
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = LEVEL0;
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;

    CTC_ERROR_RETURN(sys_usw_opf_init_offset(lchip, &opf, 0, max_size));

    /* 3. init bucket array */
    NALPM2_BUCKET_L0(lchip).bucket = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_bucket_l0_t*) * (max_size / NALPM2_BUCKET_BSIZE + 1), sys_nalpm2_bucket_l0_t);
    if (NULL == NALPM2_BUCKET_L0(lchip).bucket)
    {
        goto error0;
    }
    sal_memset(NALPM2_BUCKET_L0(lchip).bucket, 0, sizeof(sys_nalpm2_bucket_l0_t*) * (max_size / NALPM2_BUCKET_BSIZE + 1));

    for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
    {
        NALPM2_BUCKET_L0(lchip).bucket[i] = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_bucket_l0_t) * NALPM2_BUCKET_BSIZE, sys_nalpm2_bucket_l0_t);
        if (NULL == NALPM2_BUCKET_L0(lchip).bucket[i])
        {
            goto error0;
        }
        sal_memset(NALPM2_BUCKET_L0(lchip).bucket[i], 0, sizeof(sys_nalpm2_bucket_l0_t)*NALPM2_BUCKET_BSIZE);
    }

    /* 4. init bucket list */
    entry_num = NALPM2_BUCKET_MAX_ENTRY_L0(lchip) + 1;

    NALPM2_BUCKET_L0(lchip).bkt_use_list = mem_malloc2(MEM_IPUC_MODULE, sizeof(ctc_list_pointer_t) * entry_num, ctc_list_pointer_t);
    if (NULL == NALPM2_BUCKET_L0(lchip).bkt_use_list)
    {
        goto error0;
    }

    for (i = 0; i < entry_num; i++)
    {
        ctc_list_pointer_init(&NALPM2_BUCKET_L0(lchip).bkt_use_list[i]);
    }

    return CTC_E_NONE;

error0:
    if (g_sys_nalpm2_master[lchip]->bkt_l0.bkt_use_list)
    {
        mem_free(g_sys_nalpm2_master[lchip]->bkt_l0.bkt_use_list);
    }

    if (g_sys_nalpm2_master[lchip]->bkt_l0.bucket)
    {
        for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
        {
            if (NULL != g_sys_nalpm2_master[lchip]->bkt_l0.bucket[i])
            {
                mem_free(g_sys_nalpm2_master[lchip]->bkt_l0.bucket[i]);
            }
        }
        mem_free(g_sys_nalpm2_master[lchip]->bkt_l0.bucket);
    }

    return CTC_E_NO_MEMORY;
}

int32
_sys_nalpm2_bucket_init_l1(uint8 lchip)
{
    sys_usw_opf_t opf;
    uint32 entry_num = 0;
    uint32 max_size = 0;
    uint16 i = 0;

    /* 1. get table entry num */
    CTC_ERROR_RETURN(sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake_t, &entry_num));

    /* 2. prepare data */
    NALPM2_BUCKET_L1(lchip).bkt_depth = 16*1024;
    NALPM2_BUCKET_L1(lchip).snake_group_num = g_sys_nalpm2_master[lchip]->ipsa_enable ? 1 : 2;
    NALPM2_BUCKET_L1(lchip).snake_per_group = (entry_num / NALPM2_BUCKET_L1(lchip).bkt_depth);
    if(!NALPM2_BUCKET_L1(lchip).snake_per_group)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "LPM L1 sram not enough!!!");
        return CTC_E_NO_RESOURCE;
    }
    MCHIP_CAP(SYS_CAP_SPEC_LPM_ROUTE_ENTRY_NUM) = NALPM2_BUCKET_L1(lchip).bkt_depth *
                                                  NALPM2_BUCKET_L1(lchip).snake_group_num *
                                                  NALPM2_BUCKET_L1(lchip).snake_per_group *
                                                  ROUTE_NUM_PER_SNAKE_V4;

    NALPM2_BUCKET_L1(lchip).real_bkt_depth = NALPM2_BUCKET_L1(lchip).bkt_depth;
    NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V4] = 6;
    NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V6_64] = 3;
    NALPM2_BUCKET_L1(lchip).snake_fmt_num[NALPM2_FMT_V6_128] = 2;
    NALPM2_BUCKET_L1(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V4_32] = DsNeoLpmIpv4Bit32Snake_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V6_64] = DsNeoLpmIpv6Bit64Snake_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V6_128] = DsNeoLpmIpv6Bit128Snake_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[0][SYS_NALPM2_SRAM_TYPE_V4_EXT] = DsNeoLpmIpv4Bit32SnakeExt_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V4_32] = DsNeoLpmIpv4Bit32Snake1_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V6_64] = DsNeoLpmIpv6Bit64Snake1_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V6_128] = DsNeoLpmIpv6Bit128Snake1_t;
    NALPM2_BUCKET_L1(lchip).tbl_id[1][SYS_NALPM2_SRAM_TYPE_V4_EXT] = DsNeoLpmIpv4Bit32SnakeExt1_t;

    max_size = NALPM2_BUCKET_L1(lchip).real_bkt_depth;

    /* 2. init sram index opf */
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
    opf.pool_index = LEVEL1;
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;

    CTC_ERROR_RETURN(sys_usw_opf_init_offset(lchip, &opf, 0, max_size));

    /* 3. init bucket array */
    NALPM2_BUCKET_L1(lchip).bucket = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_bucket_l1_t*) * (max_size / NALPM2_BUCKET_BSIZE + 1), sys_nalpm2_bucket_l1_t);
    if (NULL == NALPM2_BUCKET_L1(lchip).bucket)
    {
        goto error0;
    }

    sal_memset(NALPM2_BUCKET_L1(lchip).bucket, 0, sizeof(sys_nalpm2_bucket_l1_t *) * (max_size / NALPM2_BUCKET_BSIZE + 1));

    for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
    {
        NALPM2_BUCKET_L1(lchip).bucket[i] = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_bucket_l1_t) * NALPM2_BUCKET_BSIZE, sys_nalpm2_bucket_l1_t);
        if (NULL == NALPM2_BUCKET_L1(lchip).bucket[i])
        {
            goto error0;
        }
        sal_memset(NALPM2_BUCKET_L1(lchip).bucket[i], 0, sizeof(sys_nalpm2_bucket_l1_t) * NALPM2_BUCKET_BSIZE);
    }

    /* 4. init bucket list */
    entry_num = NALPM2_BUCKET_MAX_ENTRY_L1(lchip) + 1;
    NALPM2_BUCKET_L1(lchip).bkt_use_list = mem_malloc2(MEM_IPUC_MODULE, sizeof(ctc_list_pointer_t) * entry_num, ctc_list_pointer_t);
    if (NULL == NALPM2_BUCKET_L1(lchip).bkt_use_list)
    {
        goto error0;
    }
    for (i = 0; i < entry_num; i++)
    {
        ctc_list_pointer_init(&NALPM2_BUCKET_L1(lchip).bkt_use_list[i]);
    }

    return CTC_E_NONE;

error0:
    if (g_sys_nalpm2_master[lchip]->bkt_l1.bkt_use_list)
    {
        mem_free(g_sys_nalpm2_master[lchip]->bkt_l1.bkt_use_list);
    }

    if (g_sys_nalpm2_master[lchip]->bkt_l1.bucket)
    {
        for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
        {
            if (NULL != g_sys_nalpm2_master[lchip]->bkt_l1.bucket[i])
            {
                mem_free(g_sys_nalpm2_master[lchip]->bkt_l1.bucket[i]);
            }
        }
        mem_free(g_sys_nalpm2_master[lchip]->bkt_l1.bucket);
    }

    return CTC_E_NO_MEMORY;
}

int32
_sys_nalpm2_bucket_deinit_l0(uint8 lchip)
{
    uint32 i = 0;
    uint32 max_size = NALPM2_BUCKET_L0(lchip).real_bkt_depth;

    for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
    {
        mem_free(NALPM2_BUCKET_L0(lchip).bucket[i]);
    }

    mem_free(NALPM2_BUCKET_L0(lchip).bucket);
    mem_free(NALPM2_BUCKET_L0(lchip).bkt_use_list);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_bucket_deinit_l1(uint8 lchip)
{
    uint32 i = 0;
    uint32 max_size = NALPM2_BUCKET_L1(lchip).real_bkt_depth;

    for (i = 0; i < (max_size / NALPM2_BUCKET_BSIZE + 1); i++)
    {
        mem_free(NALPM2_BUCKET_L1(lchip).bucket[i]);
    }

    mem_free(NALPM2_BUCKET_L1(lchip).bucket);
    mem_free(NALPM2_BUCKET_L1(lchip).bkt_use_list);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_bucket_list_update_l0(uint8 lchip, uint16 sram_idx, int32 incr_cnt)
{
     uint32 old_cnt = 0;
     uint32 new_cnt = 0;

     old_cnt = NALPM2_BUCKET_USE_CNT_L0(lchip, sram_idx);

     if (old_cnt)
     {
         ctc_list_pointer_delete(&NALPM2_BUCKET_USE_LIST_L0(lchip, old_cnt),
                                 (ctc_list_pointer_node_t*)&NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx));
     }

     NALPM2_BUCKET_USE_CNT_L0(lchip, sram_idx) +=  incr_cnt;

     new_cnt = NALPM2_BUCKET_USE_CNT_L0(lchip, sram_idx);

     if (new_cnt)
     {
         ctc_list_pointer_insert_tail(&NALPM2_BUCKET_USE_LIST_L0(lchip, new_cnt),
                                      (ctc_list_pointer_node_t*)&NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx));
     }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_bucket_list_update_l1(uint8 lchip, uint16 sram_idx, int32 incr_cnt)
{
     uint32 old_cnt = 0;
     uint32 new_cnt = 0;

     old_cnt = NALPM2_BUCKET_USE_CNT_L1(lchip, sram_idx);

     if (old_cnt)
     {
         ctc_list_pointer_delete(&NALPM2_BUCKET_USE_LIST_L1(lchip, old_cnt),
                                 (ctc_list_pointer_node_t*)&NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx));
     }

     NALPM2_BUCKET_USE_CNT_L1(lchip, sram_idx) += incr_cnt;

     new_cnt = NALPM2_BUCKET_USE_CNT_L1(lchip, sram_idx);

     if (new_cnt)
     {
         ctc_list_pointer_insert_tail(&NALPM2_BUCKET_USE_LIST_L1(lchip, new_cnt),
                                      (ctc_list_pointer_node_t*)&NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx));
     }

    return CTC_E_NONE;
}

#define _______Cookie_______

int32
_sys_nalpm2_recreate_cookie(trie_node_t * node, void *data)
{
    sys_nalpm2_cookie_t* p_cookie = data;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = CONTAINER_OF(node, sys_nalpm2_trie_l0_info_t, node);
    sys_nalpm2_tcam_item_t* p_tcam_item = p_cookie->p_install_tcam;
    sys_nalpm2_info_t* p_l0_info = NULL;
    uint8 lchip = p_cookie->lchip;

    if (INTERNAL == node->type)
    {
        return CTC_E_NONE;
    }
    p_l0_info = p_trie_l0_info->p_l0_info;

    _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_l0_info, p_l0_info->hw_position[0], p_l0_info->hw_position[1], 0,
                        p_cookie->is_new_trie ? p_cookie->ds_snake_new[p_l0_info->hw_position[0]] : p_cookie->ds_snake[p_l0_info->hw_position[0]],
                        p_cookie->is_new_trie ? p_cookie->ds_snake_new_mask[p_l0_info->hw_position[0]] : p_cookie->ds_snake_mask[p_l0_info->hw_position[0]]);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_create_cookie_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_tcam_item_t* p_tcam_item_new, sys_nalpm2_cookie_t** pp_cookie)
{
    sys_nalpm2_cookie_t* p_cookie = NULL;
    #if (1 == SDK_WORK_PLATFORM)
    uint32 tbl_id1 = 0;
    uint32 tbl_id = 0;
    uint32 hw_idx = 0;
    uint32 cmd = 0;
    uint8 i = 0;
    #endif

    /* 0. prepare data */
    p_cookie = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_cookie_t), sys_nalpm2_cookie_t);
    if (!p_cookie)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_cookie, 0, sizeof(sys_nalpm2_cookie_t));

    /* 1. Read Hardware to DB */
    #if (1 == SDK_WORK_PLATFORM)
    i = 0;
    do
    {
        if (p_tcam_item)
        {
            _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item->sram_idx, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]));
        }
        if (p_tcam_item_new && (p_tcam_item_new->sub_bkt >= 1))
        {
            _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item_new->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item_new->sram_idx, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]));
        }

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    #endif

    /* 2. set output data */
    *pp_cookie = p_cookie;

    return CTC_E_NONE;
}

int32
_sys_nalpm2_create_cookie_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_l0_item_t* p_l0_item_new, sys_nalpm2_cookie_t** pp_cookie)
{
    sys_nalpm2_cookie_t* p_cookie = NULL;
    #if (1 == SDK_WORK_PLATFORM)
    uint32 tbl_id1 = 0;
    uint32 tbl_id = 0;
    uint32 hw_idx = 0;
    uint32 cmd = 0;
    uint8 i = 0;
    #endif

    /* 0. prepare data */
    p_cookie =  mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_cookie_t), sys_nalpm2_cookie_t);
    if (!p_cookie)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_cookie, 0, sizeof(sys_nalpm2_cookie_t));

    /* 1. Read Hardware to DB */
    #if (1 == SDK_WORK_PLATFORM)
    i = 0;
    do
    {
        if (p_l0_item)
        {
            _sys_nalpm2_get_table_id_l1(lchip, p_l0_item->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item->sram_idx, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]));
        }
        if (p_l0_item_new && p_l0_item_new->sub_bkt >= 1)
        {
            _sys_nalpm2_get_table_id_l1(lchip, p_l0_item_new->sram_type, i, &tbl_id, &tbl_id1);
            cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
            hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item_new->sram_idx, i);
            CTC_ERROR_RETURN(DRV_IOCTL(lchip, hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]));
        }

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    #endif

    /* 2. set output data */
    *pp_cookie = p_cookie;

    return CTC_E_NONE;
}

int32
_sys_nalpm2_write_route_cookie_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_tcam_item_t* p_tcam_item_new, sys_nalpm2_cookie_t* p_cookie)
{
    #if (1 != SDK_WORK_PLATFORM)
    tbl_entry_t tbl_entry;
    #endif
    uint32 tbl_id1 = 0;
    uint32 hw_idx = 0;
    uint32 tbl_id = 0;
    uint32 cmd1 = 0;
    uint32 cmd = 0;
    uint8 i = 0;
    uint8 loop_lchip = 0;

    /* 1. write DB to Hardware */
    i = 0;
    do
    {
        if (p_tcam_item)
        {
            _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item->sram_type, i, &tbl_id, &tbl_id1);
            hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item->sram_idx, i);

            #if (1 == SDK_WORK_PLATFORM)
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]);
                DO_SLAVE_LOOP_END
            }
            #else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_mask[i];

            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
                DO_SLAVE_LOOP_END
            }
            #endif
        }

        if (p_tcam_item_new)
        {
            _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item_new->sram_type, i, &tbl_id, &tbl_id1);
            hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item_new->sram_idx, i);

            #if (1 == SDK_WORK_PLATFORM)
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]);
                DO_SLAVE_LOOP_END
            }
            #else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake_new[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_new_mask[i];

            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
                DO_SLAVE_LOOP_END
            }
            #endif
        }

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    return 0;
}

int32
_sys_nalpm2_write_route_cookie_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_l0_item_t* p_l0_item_new, sys_nalpm2_cookie_t* p_cookie)
{
    #if (1 != SDK_WORK_PLATFORM)
    tbl_entry_t tbl_entry;
    #endif
    uint32 tbl_id1 = 0;
    uint32 hw_idx = 0;
    uint32 tbl_id = 0;
    uint32 cmd1 = 0;
    uint32 cmd = 0;
    uint8 i = 0;
    uint8 loop_lchip = 0;

    /* 1. write DB to Hardware */
    i = 0;
    do
    {
        if (p_l0_item)
        {
            _sys_nalpm2_get_table_id_l1(lchip, p_l0_item->sram_type, i, &tbl_id, &tbl_id1);
            hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item->sram_idx, i);

            #if (1 == SDK_WORK_PLATFORM)
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake[i]);
                DO_SLAVE_LOOP_END
            }
            #else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_mask[i];

            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
                DO_SLAVE_LOOP_END
            }
            #endif
        }

        if (p_l0_item_new)
        {
            _sys_nalpm2_get_table_id_l1(lchip, p_l0_item_new->sram_type, i, &tbl_id, &tbl_id1);
            hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item_new->sram_idx, i);

            #if (1 == SDK_WORK_PLATFORM)
            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), p_cookie->ds_snake_new[i]);
                DO_SLAVE_LOOP_END
            }
            #else
            tbl_entry.data_entry = (uint32*)p_cookie->ds_snake_new[i];
            tbl_entry.mask_entry = (uint32*)p_cookie->ds_snake_new_mask[i];

            cmd = DRV_IOW(tbl_id, DRV_ENTRY_FLAG);
            DO_SLAVE_LOOP_START
            DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
            DO_SLAVE_LOOP_END

            if (g_sys_nalpm2_master[lchip]->ipsa_enable)
            {
                cmd1 = DRV_IOW(tbl_id1, DRV_ENTRY_FLAG);
                DO_SLAVE_LOOP_START
                DRV_IOCTL(lchip + (loop_lchip * SYS_PP_NUM(lchip)), hw_idx, DRV_CMD_BMP_EN(cmd1, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), &tbl_entry);
                DO_SLAVE_LOOP_END
            }
            #endif
        }

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return 0;
}

int32
_sys_nalpm2_route_install_element_l0(trie_node_t* node, void *data)
{
    sys_nalpm2_cookie_t* p_cookie = data;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = CONTAINER_OF(node, sys_nalpm2_trie_l0_info_t, node);
    sys_nalpm2_tcam_item_t* p_tcam_item = p_cookie->p_install_tcam;
    sys_nalpm2_info_t* p_l0_info = NULL;
    uint8 i = 0, j = 0, hw_i = 0, hw_j = 0;
    uint8 lchip = p_cookie->lchip;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_trie_l0_info = [%p], node = [%p],p_l0_info = [%p]\n", p_trie_l0_info, node, p_trie_l0_info->p_l0_info);

    /* 0. prepare data */
    if (node->type != PAYLOAD)
    {
        return CTC_E_NONE;
    }
    p_l0_info = p_trie_l0_info->p_l0_info;
    hw_i = p_l0_info->hw_position[0];
    hw_j = p_l0_info->hw_position[1];

    /* 1. write sram DB */
    if (p_cookie->merge_cnt)
    {
        if (p_tcam_item->p_l0_info_array[hw_i][hw_j] != p_l0_info)
        {
            /* 1.1 clear old */
            CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L0(lchip, p_cookie->p_chd_tcam->sram_idx).bitmap[hw_i], hw_j);

            /* 1.2 merge new */
            i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
            j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);
            p_tcam_item->p_l0_info_array[i][j] = p_l0_info;
            CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);
            p_l0_info->hw_position[0] = i;
            p_l0_info->hw_position[1] = j;

            if (p_l0_info->p_l0_item)
            {
                p_l0_info->p_l0_item->p_tcam_item = p_tcam_item;
            }
        }
    }
    else if (p_cookie->new_tcam)
    {
        /* 1.1 set new info */
        if (hw_i == 0xFF && hw_j == 0xFF)
        {
            p_cookie->p_l0_info_new = p_l0_info;
            p_cookie->route_in_new_trie = 1;
        }
        /* 1.2 set clear array using splited trie position of old trie */
        else
        {
            p_cookie->clear_array[p_cookie->clear_cnt++] = (hw_i << 8 | hw_j);
        }

        /* 1.3 set new trie position from index array */
        i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
        j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);

        /* 1.4 set new trie info array */
        p_tcam_item->p_l0_info_array[i][j] = p_l0_info;

        /* 1.5 set bucket bitmap of new trie */
        CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        /* 1.6 update info position */
        p_l0_info->hw_position[0] = i;
        p_l0_info->hw_position[1] = j;

        /* 1.7 point to tcam item */
        if (p_l0_info->p_l0_item)
        {
            p_l0_info->p_l0_item->p_tcam_item = p_tcam_item;
        }

        /* 1.8 set cookie snake DB */
        _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_l0_info, i, j, 0, p_cookie->ds_snake_new[i], p_cookie->ds_snake_new_mask[i]);
    }
    else
    {
        if (hw_i == 0xFF && hw_j == 0xFF)
        {
            p_cookie->p_l0_info_new = p_l0_info;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_route_install_element_l1(trie_node_t* node, void *data)
{
    sys_nalpm2_cookie_t* p_cookie = data;
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info = CONTAINER_OF(node, sys_nalpm2_trie_l1_info_t, node);
    sys_nalpm2_l0_item_t* p_l0_item = p_cookie->p_install_l0;
    sys_ipuc_info_t* p_l1_info = NULL;
    uint8 i = 0, j = 0,  hw_i = 0, hw_j = 0;
    uint8 lchip = p_cookie->lchip;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n", __FUNCTION__);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "p_trie_l1_info = [%p], node = [%p], p_l1_info = [%p]\n", p_trie_l1_info, node , p_trie_l1_info->p_l1_info);

    /* 0. prepare data */
    if (node->type != PAYLOAD)
    {
        return CTC_E_NONE;
    }
    p_l1_info = p_trie_l1_info->p_l1_info;
    hw_i = p_l1_info->snake_idx;
    hw_j = p_l1_info->entry_offset;

    /* 1. write sram DB */
    if (p_cookie->merge_cnt)
    {
        if (p_l0_item->p_l1_info_array[hw_i][hw_j] != p_l1_info)
        {
            /* 1.1 clear old */
            CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L1(lchip, p_cookie->p_chd_l0->sram_idx).bitmap[hw_i], hw_j);

            /* 1.2 merge new */
            i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
            j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);
            p_l0_item->p_l1_info_array[i][j] = p_l1_info;
            CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i], j);
            p_l1_info->snake_idx = i;
            p_l1_info->entry_offset = j;
        }
    }
    else if (p_cookie->new_tcam)
    {
        /* 1.1 set new info */
        if (hw_i == 0xFF && hw_j == 0xFF )
        {
            p_cookie->p_l1_info_new = p_l1_info;
            p_cookie->route_in_new_trie = 1;
        }
        /* 1.2 set clear array using splited trie position of old trie */
        else
        {
            p_cookie->clear_array[p_cookie->clear_cnt++] = (hw_i << 8 | hw_j);
        }

        /* 1.3 set new trie position from index array */
        i = (p_cookie->index_array[p_cookie->cur_idx] >> 8);
        j = (p_cookie->index_array[p_cookie->cur_idx++] & 0xFF);

        /* 1.4 set new trie info array */
        p_l0_item->p_l1_info_array[i][j] = p_l1_info;

        /* 1.5 set bucket bitmap of new trie */
        CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i], j);

        /* 1.6 update info position */
        p_l1_info->snake_idx = i;
        p_l1_info->entry_offset = j;
        p_l1_info->sram_idx = p_l0_item->sram_idx;
        p_l1_info->sub_bkt = p_l0_item->sub_bkt;

        /* 1.7 set cookie snake DB */
        _sys_nalpm2_write_sram_l1(lchip, p_l0_item, p_l1_info, i, j, 0, p_cookie->ds_snake_new[i], p_cookie->ds_snake_new_mask[i]);
    }
    else
    {
        if (hw_i == 0xFF &&  hw_j == 0xFF )
        {
            p_cookie->p_l1_info_new = p_l1_info;
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_reinstall_element_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_cookie_t* p_cookie)
{
    sys_nalpm2_info_t* p_l0_info_new = NULL;
    sys_nalpm2_info_tmp_t route_info_void2;
    sys_nalpm2_info_t* route_info_void = (sys_nalpm2_info_t*)&route_info_void2;
    uint8 ip_ver = p_tcam_item->p_l0_root_info->ip_ver;
    uint8 idx = 0;
    uint8 i = 0;
    uint8 j = 0;

    sal_memset(&route_info_void2, 0, sizeof(sys_nalpm2_info_tmp_t));
    route_info_void->ip_ver = ip_ver;

    /* 1. clear sram */
    idx = 0;
    do
    {
        if (!p_cookie->clear_cnt)
        {
            break;
        }
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx] & 0xFF);
        p_tcam_item->p_l0_info_array[i][j] = NULL;
        CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, route_info_void, i, j, 0, p_cookie->ds_snake[i], p_cookie->ds_snake_mask[i]);

        idx++;

    } while (idx < p_cookie->clear_cnt);

    p_l0_info_new = p_cookie->p_l0_info_new;

    /* 2. set new l0 info to sram */
    if (!p_cookie->route_in_new_trie && p_l0_info_new->hw_position[0] == 0xff)
    {
        _sys_nalpm2_find_best_position_l0(lchip, p_tcam_item, 0, &i, &j);

        p_tcam_item->p_l0_info_array[i][j] = p_l0_info_new;
        p_l0_info_new->hw_position[0] = i;
        p_l0_info_new->hw_position[1] = j;
        CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_l0_info_new, i, j, 0, p_cookie->ds_snake[i], p_cookie->ds_snake_mask[i]);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_reinstall_element_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_cookie_t* p_cookie)
{
    sys_ipuc_info_t* p_l1_info_new = NULL;
    sys_ipuc_info_t route_info_void;
    uint8 idx = 0;
    uint8 i = 0;
    uint8 j = 0;

    sal_memset(&route_info_void, 0, sizeof(sys_ipuc_info_t));

    /* 1. clear sram */
    idx = 0;
    do
    {
        if (!p_cookie->clear_cnt)
        {
            break;
        }
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx] & 0xFF);
        p_l0_item->p_l1_info_array[i][j] = NULL;
        CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i], j);

        _sys_nalpm2_write_sram_l1(lchip, p_l0_item, &route_info_void, i, j, 0, p_cookie->ds_snake[i], p_cookie->ds_snake_mask[i]);

        idx++;

    } while (idx < p_cookie->clear_cnt);

    p_l1_info_new = p_cookie->p_l1_info_new;

    if (p_l1_info_new && !p_cookie->route_in_new_trie && p_l1_info_new->snake_idx == 0xff)
    {
        _sys_nalpm2_find_best_position_l1(lchip, p_l0_item, 0, &i, &j);

        p_l0_item->p_l1_info_array[i][j] = p_l1_info_new;
        p_l1_info_new->snake_idx = i;
        p_l1_info_new->entry_offset = j;
        p_l1_info_new->sram_idx = p_l0_item->sram_idx;
        p_l1_info_new->sub_bkt = p_l0_item->sub_bkt;
        CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i], j);

        _sys_nalpm2_write_sram_l1(lchip, p_l0_item, p_l1_info_new, i, j, 0, p_cookie->ds_snake[i], p_cookie->ds_snake_mask[i]);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_alloc_offset_array_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_cookie_t* p_cookie)
{
    uint32 sram_idx = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 stop_cnt = 0;
    uint8 i = 0, j = 0;
    uint8 idx = 0;

    sram_idx = p_tcam_item->sram_idx;
    stop_cnt = p_cookie->merge_cnt ? p_cookie->merge_cnt : p_tcam_item->trie->trie->count;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        if (NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i] == _sys_nalpm2_get_snake_bitwdith(lchip, p_tcam_item->sram_type))
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i], j))
            {
                j++;
                continue;
            }

            p_cookie->index_array[idx++] = (i << 8 | j);   /* index_array[maxRouteNum] = snake_index << 8 | route_entry_index */

            if (idx == stop_cnt)
            {
                return 0;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    return 0;
}

int32
_sys_nalpm2_alloc_offset_array_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_cookie_t* p_cookie)
{
    uint32 sram_idx = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    uint8 stop_cnt = 0;
    uint8 i = 0, j = 0;
    uint8 idx = 0;

    sram_idx = p_l0_item->sram_idx;
    stop_cnt = p_cookie->merge_cnt ? p_cookie->merge_cnt : p_l0_item->trie->trie->count;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l1(lchip, p_l0_item->sram_type);
    snake_entry_cnt = route_per_snake;

    i = 0;
    do
    {
        if (NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap[i] == _sys_nalpm2_get_snake_bitwdith(lchip, p_l0_item->sram_type))
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap[i], j))
            {
                j++;
                continue;
            }

            p_cookie->index_array[idx++] = (i << 8 | j);   /* index_array[maxRouteNum] = snake_index << 8 | route_entry_index */

            if (idx == stop_cnt)
            {
                return 0;
            }

            j++;

        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return 0;
}

int32
_sys_nalpm2_renew_route_trie_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_cookie_t* p_cookie, uint8 new_tcam)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_cookie->p_install_tcam = p_tcam_item;
    p_cookie->new_tcam = new_tcam;
    p_cookie->lchip = lchip;
    p_cookie->ln = LEVEL0;

    if(new_tcam)
    {
        sal_memset(p_tcam_item->p_l0_info_array, 0, sizeof(p_tcam_item->p_l0_info_array));
    }

    CTC_ERROR_RETURN(sys_nalpm_trie_traverse(p_tcam_item->trie->trie, _sys_nalpm2_route_install_element_l0, (void*)p_cookie, _TRIE_INORDER_TRAVERSE));

    return CTC_E_NONE;
}

int32
_sys_nalpm2_renew_route_trie_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_cookie_t* p_cookie, uint8 new_tcam)
{
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_cookie->p_install_l0 = p_l0_item;
    p_cookie->new_tcam = new_tcam;
    p_cookie->lchip = lchip;
    p_cookie->ln = LEVEL1;

    if(new_tcam)
    {
        sal_memset(p_l0_item->p_l1_info_array, 0, sizeof(p_l0_item->p_l1_info_array));
    }

    CTC_ERROR_RETURN(sys_nalpm_trie_traverse(p_l0_item->trie->trie, _sys_nalpm2_route_install_element_l1, (void*)p_cookie, _TRIE_INORDER_TRAVERSE));
    return ret;
}

int32
_sys_nalpm2_clear_snake_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    /*clear snake*/
    sys_nalpm2_cookie_t cookie;

    sal_memset(&cookie, 0, sizeof(sys_nalpm2_cookie_t));

    _sys_nalpm2_write_route_cookie_l0(lchip, p_tcam_item, NULL, &cookie);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_clear_snake_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item)
{
    /*clear snake*/
    sys_nalpm2_cookie_t cookie;

    sal_memset(&cookie, 0, sizeof(sys_nalpm2_cookie_t));

    _sys_nalpm2_write_route_cookie_l1(lchip, p_l0_item, NULL, &cookie);

    return CTC_E_NONE;
}

#define _______CORE_______

int32
_sys_nalpm2_ln_pivot_insert_l0(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_tcam_item_t** p_tcam_item)
{
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item_temp = NULL;
    sys_nalpm2_info_t* p_l0_root_info = NULL;
    trie_t *prefix_trie = NULL;
    int32 ret = CTC_E_NONE;
    uint32 pfx[4] = {0};
    uint32 pfx_len = 0;
    uint16 sram_idx = 0;
    uint16 vrf_id = 0;
    uint8 sub_idx = 0;
    uint8  ip_ver = 0;
    uint8 msl =0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    p_trie_tcam_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_tcam_item_t), sys_nalpm2_trie_tcam_item_t);
    if(NULL == p_trie_tcam_item)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(p_trie_tcam_item, 0, sizeof(sys_nalpm2_trie_tcam_item_t));

    p_l0_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_l0_root_info)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(p_l0_root_info, 0, NALPM2_INFO_SIZE(ip_ver));

    /* 1. create new node of tcam item trie */
    CTC_ERROR_GOTO(_sys_nalpm2_sram_idx_alloc_l0(lchip, ip_ver, &sram_idx, &sub_idx, 1), ret, error0);
    p_l0_root_info->ip_ver = ip_ver;
    p_l0_root_info->vrf_id = vrf_id;
    p_l0_root_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    p_tcam_item_temp = &(p_trie_tcam_item->tcam_item);
    p_tcam_item_temp->p_l0_root_info = p_l0_root_info;
    p_tcam_item_temp->sram_idx = sram_idx;
    p_tcam_item_temp->sub_bkt = sub_idx;
    p_tcam_item_temp->p_l0_root_AD = NULL;
    NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).p_tcam_item[sub_idx] = p_tcam_item_temp;
    NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).is_root = 1;

    /* 2. set sram type */
    if (CTC_IP_VER_4 == ip_ver)
    {
        msl = SYS_NALPM2_V4_MASK_LEN_MAX;
        _sys_nalpm2_set_sram_type_l0(lchip, ip_ver, 0, p_tcam_item_temp);
    }
    else
    {
        msl = SYS_NALPM2_V6_MASK_LEN_MAX;
    }

    /* 3. alloc tcam index */
    CTC_ERROR_GOTO(_sys_nalpm2_tcam_idx_alloc(lchip, p_ipuc_param, p_tcam_item_temp), ret, error1);

    /* 4. create tcam item trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]), ret, error2);
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, pfx, NULL, pfx_len, (trie_node_t *)p_trie_tcam_item, 0), ret, error3);

    /* 5. create l0 info trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl , &p_tcam_item_temp->trie), ret, error4);

    *p_tcam_item = p_tcam_item_temp;

    return ret;


error4:
    sys_nalpm_trie_delete(prefix_trie, pfx, pfx_len, (trie_node_t **)&p_trie_tcam_item, 0);

error3:
    sys_nalpm_trie_destroy(prefix_trie);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id] = NULL;

error2:
    _sys_nalpm2_tcam_idx_free(lchip, p_ipuc_param, p_tcam_item_temp);

error1:
    _sys_nalpm2_sram_idx_free_l0(lchip, sram_idx, ip_ver);

error0:
    if(p_trie_tcam_item)
        mem_free(p_trie_tcam_item);
    if(p_l0_root_info)
        mem_free(p_l0_root_info);

    return ret;
}

int32
_sys_nalpm2_ln_pivot_insert_l1(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_l0_item_t** p_l0_item)
{
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_temp = NULL;
    trie_t *prefix_trie = NULL;
    int32 ret = CTC_E_NONE;
    uint32 pfx[4] = {0};
    uint32 pfx_len = 0;
    uint16 sram_idx = 0;
    uint16 vrf_id = 0;
    uint8 sub_idx = 0;
    uint8 ip_ver = 0;
    uint8 msl =0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    p_trie_l0_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_item_t), sys_nalpm2_trie_l0_item_t);
    if(NULL == p_trie_l0_item)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(p_trie_l0_item, 0, sizeof(sys_nalpm2_trie_l0_item_t));

    p_l1_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_l1_root_info)
    {
        ret =  CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(p_l1_root_info, 0, NALPM2_INFO_SIZE(ip_ver));

    /* 1. create new node of l0 item trie */
    CTC_ERROR_GOTO(_sys_nalpm2_sram_idx_alloc_l1(lchip, ip_ver, &sram_idx, &sub_idx, 1), ret, error0);
    p_l1_root_info->ip_ver = ip_ver;
    p_l1_root_info->vrf_id = vrf_id;
    p_l1_root_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    p_l0_item_temp = &(p_trie_l0_item->l0_item);
    p_l0_item_temp->p_l1_root_info = p_l1_root_info;
    p_l0_item_temp->sram_idx = sram_idx;
    p_l0_item_temp->sub_bkt = sub_idx;
    p_l0_item_temp->p_l1_root_AD = NULL;
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).p_l0_item[sub_idx] = p_l0_item_temp;
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).is_root = 1;

    /* 2. set sram type */
    if (CTC_IP_VER_4 == ip_ver)
    {
        msl = SYS_NALPM2_V4_MASK_LEN_MAX;
        _sys_nalpm2_set_sram_type_l1(lchip, ip_ver, 0, p_l0_item_temp);
    }
    else
    {
        msl = SYS_NALPM2_V6_MASK_LEN_MAX;
    }

    /* 3. create l0 item trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]), ret, error1);
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, pfx, NULL, pfx_len, (trie_node_t *)p_trie_l0_item, 0), ret, error2);

    /* 4. create l0 info trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &p_l0_item_temp->trie), ret, error3);

    *p_l0_item = p_l0_item_temp;

    return ret;

error3:
    sys_nalpm_trie_delete(prefix_trie, pfx, pfx_len, (trie_node_t **)&p_trie_l0_item, 0);

error2:
    sys_nalpm_trie_destroy(prefix_trie);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id] = NULL;

error1:
    _sys_nalpm2_sram_idx_free_l1(lchip, sram_idx, ip_ver);

error0:
    if(p_trie_l0_item)
        mem_free(p_trie_l0_item);
    if(p_l1_root_info)
        mem_free(p_l1_root_info);

    return ret;
}

int32
_sys_nalpm2_ln_pivot_del_l0(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param)
{
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    trie_t *prefix_trie = NULL;
    uint32 pfx[4] = {0};
    uint16 vrf_id = 0;
    uint8  ip_ver = 0;

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id];
    p_trie_tcam_item = CONTAINER_OF(prefix_trie->trie, sys_nalpm2_trie_tcam_item_t, node);
    p_tcam_item = &p_trie_tcam_item->tcam_item;

    /* 1. destroy trie */
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_tcam_item->trie));
    CTC_ERROR_RETURN(sys_nalpm_trie_delete(prefix_trie, pfx, 0, (trie_node_t **) &p_trie_tcam_item, 0));
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(prefix_trie));
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id] = NULL;

    /* 2. free tcam index */
    CTC_ERROR_RETURN(_sys_nalpm2_tcam_idx_free(lchip, p_ipuc_param, p_tcam_item));

    /* 3. free sram index */
    CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free_l0(lchip, p_tcam_item->sram_idx, ip_ver));

    if (p_trie_tcam_item->tcam_item.p_l0_root_info)
    {
        mem_free(p_trie_tcam_item->tcam_item.p_l0_root_info);
    }
    mem_free(p_trie_tcam_item);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_ln_pivot_del_l1(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param)
{
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    trie_t *prefix_trie = NULL;
    uint32 pfx[4] = {0};
    uint16 vrf_id = 0;
    uint8  ip_ver = 0;

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id];
    p_trie_l0_item = CONTAINER_OF(prefix_trie->trie, sys_nalpm2_trie_l0_item_t, node);
    p_l0_item = &p_trie_l0_item->l0_item;

    /* 1. destroy trie */
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_l0_item->trie));
    CTC_ERROR_RETURN(sys_nalpm_trie_delete(prefix_trie, pfx, 0, (trie_node_t **) &p_trie_l0_item, 0));
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(prefix_trie));
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id] = NULL;

    /* 2. free sram index */
    CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free_l1(lchip, p_l0_item->sram_idx, ip_ver));

    if (p_trie_l0_item->l0_item.p_l1_root_info)
    {
        mem_free(p_trie_l0_item->l0_item.p_l1_root_info);
    }
    mem_free(p_trie_l0_item);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_add_directly_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_info_t* p_l0_info, sys_nalpm2_route_store_info_t *p_lkp_rlt)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_tcam_item->p_l0_info_array[p_lkp_rlt->snake_idx[LEVEL0]][p_lkp_rlt->entry_offset[LEVEL0]] = p_l0_info;

    p_l0_info->hw_position[0] = p_lkp_rlt->snake_idx[LEVEL0];
    p_l0_info->hw_position[1] = p_lkp_rlt->entry_offset[LEVEL0];

    CTC_ERROR_RETURN(_sys_nalpm2_write_sram_l0(lchip, p_tcam_item, p_l0_info, p_lkp_rlt->snake_idx[LEVEL0], p_lkp_rlt->entry_offset[LEVEL0], 0, NULL, NULL));

    CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[p_lkp_rlt->snake_idx[LEVEL0]], p_lkp_rlt->entry_offset[LEVEL0]);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_add_directly_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_info_t* p_l1_info, sys_nalpm2_route_store_info_t *p_lkp_rlt)
{
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]] = p_l1_info;

    p_l1_info->snake_idx = p_lkp_rlt->snake_idx[LEVEL1];
    p_l1_info->entry_offset = p_lkp_rlt->entry_offset[LEVEL1];

    CTC_ERROR_RETURN(_sys_nalpm2_write_sram_l1(lchip, p_l0_item, p_l1_info, p_lkp_rlt->snake_idx[LEVEL1], p_lkp_rlt->entry_offset[LEVEL1], 0, NULL, NULL));

    CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[p_lkp_rlt->snake_idx[LEVEL1]], p_lkp_rlt->entry_offset[LEVEL1]);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_check_cover_l0(trie_node_t* node, void *data)
{
    sys_nalpm2_route_cover_trav_t* p_trav_data = (sys_nalpm2_route_cover_trav_t*)data;
    sys_nalpm2_tcam_item_t* p_tcam_item_new = (sys_nalpm2_tcam_item_t*)p_trav_data->ptr1;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = CONTAINER_OF(node, sys_nalpm2_trie_l0_info_t, node);
    sys_nalpm2_info_t* p_l0_info = NULL;

    /* 0. prepare data */
    if (node->type != PAYLOAD)
    {
        return CTC_E_NONE;
    }
    p_l0_info = p_trie_l0_info->p_l0_info;
    if (p_tcam_item_new->p_l0_root_info->tcam_masklen == p_l0_info->route_masklen)
    {
        p_trav_data->value1 = 1;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_need_proccess_route_cover(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item)
{
    sys_nalpm2_route_cover_trav_t trav_data;

    sal_memset(&trav_data, 0, sizeof(sys_nalpm2_route_cover_trav_t));
    trav_data.ptr1 = p_tcam_item;
    trav_data.value1 = 0; /* if find l0 masklen same with tcam new.set to 1*/

    sys_nalpm_trie_traverse(p_tcam_item->trie->trie ,_sys_nalpm2_check_cover_l0, (void*)(&trav_data), _TRIE_INORDER_TRAVERSE);

    if(trav_data.value1)
    {
        return FALSE;
    }
    return TRUE;
}

int32
_sys_nalpm2_pick_covered_route(trie_node_t* node, void *data)
{
    sys_nalpm2_route_cover_trav_t* p_trav_data = (sys_nalpm2_route_cover_trav_t*)data;
    sys_ipuc_info_t** p_ipuc_info = ((sys_ipuc_info_t**)p_trav_data->ptr1);
    sys_nalpm2_tcam_item_t* p_tcam_item_new = (sys_nalpm2_tcam_item_t*)p_trav_data->ptr2;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_info_t* p_l0_info = NULL;
    sys_nalpm2_info_tmp_t nalpm_info_tmp;
    sys_nalpm2_info_t* p_nalpm_info = (sys_nalpm2_info_t*)&nalpm_info_tmp;
    uint8 snake_entry_cnt = 0;
    uint8 i,j;
    uint8 lchip = p_trav_data->value2;
    uint8 ip_ver = p_tcam_item_new->p_l0_root_info->ip_ver;

    if(INTERNAL == node->type)
    {
        return CTC_E_NONE;
    }
    p_trie_l0_info = CONTAINER_OF(node, sys_nalpm2_trie_l0_info_t, node);
    p_l0_info = p_trie_l0_info->p_l0_info;
    p_l0_item = p_l0_info->p_l0_item;
    if(p_l0_item->p_l1_root_info->route_masklen > p_tcam_item_new->p_l0_root_info->tcam_masklen)
    {
        return CTC_E_NONE;
    }

    if(_sys_nalpm2_route_match_l0(lchip, p_tcam_item_new->p_l0_root_info, p_l0_item->p_l1_root_info))
    {
        return CTC_E_NONE;
    }

    snake_entry_cnt = _sys_nalpm2_get_snake_route_num_l1(lchip, p_l0_item->sram_type);
    sal_memset(&nalpm_info_tmp, 0, sizeof(sys_nalpm2_info_tmp_t));
    i = 0;
    do
    {
        if(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap[i] == 0)
        {
            i++;
            continue;
        }

        j = 0;
        do
        {
            if (NULL != p_l0_item->p_l1_info_array[i][j])
            {
                sal_memcpy(p_nalpm_info->ip, &p_l0_item->p_l1_info_array[i][j]->ip, IP_ADDR_SIZE(ip_ver));
                p_nalpm_info->route_masklen = p_l0_item->p_l1_info_array[i][j]->masklen;
                p_nalpm_info->vrf_id = p_l0_item->p_l1_info_array[i][j]->vrf_id;
                p_nalpm_info->ip_ver = ip_ver;
                if(p_nalpm_info->route_masklen >= p_tcam_item_new->p_l0_root_info->tcam_masklen &&
                !_sys_nalpm2_route_match_l0(lchip, p_tcam_item_new->p_l0_root_info, p_nalpm_info))
                {
                    p_ipuc_info[p_trav_data->value1] = p_l0_item->p_l1_info_array[i][j];
                    p_trav_data->value1++;

                    if(!p_trav_data->ptr3)
                    {
                        p_trav_data->ptr3 = p_l0_item;
                    }
                    else if(p_trav_data->ptr3 != p_l0_item)
                    {
                        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "More than one l0 node has covered route!!!!\n");
                    }

                    if(p_trav_data->value1 > (SYS_NALPM2_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4))
                    {
                        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Move cnt over a whole L1 bucket!!!!\n");
                    }
                }
            }

            j++;
        } while (j < snake_entry_cnt);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return CTC_E_NONE;
}

int32
_sys_nalpm2_lkup_position_l0(uint8 lchip, sys_nalpm2_tcam_item_t *p_tcam_item, sys_nalpm2_info_t* p_l0_info)
{
    uint16 sram_idx;
    uint8 find_void_position = 0;
    uint8 snake_entry_cnt = 0;
    uint8 i = 0, j = 0;

    /* 0. prepare data */
    sram_idx = p_tcam_item->sram_idx;

    /* 1. find position or alloc position */
    snake_entry_cnt = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    i = 0;
    do
    {
        /* 1.1 alloc position */
        if (NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i] == 0)
        {
            find_void_position = 1;
            j = 0;
            break;
        }

        j = 0;
        do
        {
            if (!p_tcam_item->p_l0_info_array[i][j] || (!CTC_IS_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).bitmap[i], j)))
            {
                find_void_position = 1;
                break;
            }
            j++;
        } while (j < snake_entry_cnt);

        if(find_void_position)
        {
            break;
        }
        i++;
    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    /* 2. not found position, use alloced position */
    if (find_void_position)
    {
        p_l0_info->hw_position[0] = i;
        p_l0_info->hw_position[1] = j;
    }
    else
    {
        p_l0_info->hw_position[0] = 0xff;
        p_l0_info->hw_position[1] = 0xff;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_add_covered_l0_node(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, 
                              sys_nalpm2_tcam_item_t* p_tcam_item_new ,sys_nalpm2_l0_item_t** pp_l0_item_new,
                              sys_nalpm2_cookie_t* p_cookie_l0)
{
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_new = NULL;
    trie_t *prefix_trie = NULL;
    int32 ret = CTC_E_NONE;
    uint32 key[4] = {0};
    uint8 ip_ver = p_ipuc_param->ip_ver;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);


    if (_sys_nalpm2_sram_entry_is_full_l0(lchip, p_tcam_item_new, 1))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "insert l0 node error, new tcam is full when add l0 when proccess cover!!!");
        return CTC_E_NO_RESOURCE;
    }
    /* 0. apply for memory */
    p_l1_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if (NULL == p_l1_root_info)
    {
        return CTC_E_NO_MEMORY;
    }

    p_trie_l0_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_item_t), sys_nalpm2_trie_l0_item_t);
    if(NULL == p_trie_l0_item)
    {
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }

    sal_memset(p_l1_root_info, 0, NALPM2_INFO_SIZE(ip_ver));
    sal_memset(p_trie_l0_item, 0, sizeof(sys_nalpm2_trie_l0_item_t));

    /* 1. prepare data */
    p_l0_item_new = &p_trie_l0_item->l0_item;
    p_l0_item_new->p_l1_root_info = p_l1_root_info;
    p_l1_root_info->vrf_id = p_ipuc_param->vrf_id;
    p_l1_root_info->ip_ver = ip_ver;
    p_l1_root_info->tcam_masklen = p_tcam_item_new->p_l0_root_info->tcam_masklen;/* Tcam common prefix len */
    p_l1_root_info->route_masklen = p_l1_root_info->tcam_masklen;
    sal_memcpy(p_l1_root_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_l1_root_info = p_l0_item_new->p_l1_root_info;
    p_l1_root_info->p_l0_item = p_l0_item_new;
    if (p_l1_root_info->tcam_masklen)
    {
        SYS_NALPM2_IP_ADDR_MASK(p_l1_root_info->ip, p_l1_root_info->tcam_masklen, ip_ver)
    }
    sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key);

    /* 3. set sram type */
    _sys_nalpm2_set_sram_type_l1(lchip, ip_ver, p_l1_root_info->tcam_masklen, p_l0_item_new);

    /* 4. insert level1 trie */
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_l1_root_info->ip_ver][p_l1_root_info->vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, key, NULL, p_l1_root_info->tcam_masklen, (trie_node_t *)p_trie_l0_item, 1), ret, error1);

    /* 5. init route trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(
                  ((CTC_IP_VER_4 == ip_ver) ? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX), &p_l0_item_new->trie), ret, error2);

    /* insert to new tcam trie */
    p_trie_l0_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_info_t), sys_nalpm2_trie_l0_info_t);
    if (NULL == p_trie_l0_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error3;
    }
    sal_memset(p_trie_l0_info, 0 , sizeof(sys_nalpm2_trie_l0_info_t));
    p_trie_l0_info->p_l0_info = p_l1_root_info;

    /* TBD ,cover route need come from tcam  */

    /* sys_nalpm_trie_insert() will change key,so it need to assign again */
    sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key);
    ret = sys_nalpm_trie_insert(p_tcam_item_new->trie, key, NULL, p_l1_root_info->tcam_masklen, (trie_node_t *)p_trie_l0_info, 1);
    if (CTC_E_NONE != ret)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "!!!trie_insert failed: %d\r\n", ret);
        goto error4;
    }

    /* alloc hw position ,write l0 cookie */
    _sys_nalpm2_lkup_position_l0(lchip, p_tcam_item_new, p_l1_root_info);
    if(p_l1_root_info->hw_position[0] == 0xff && p_l1_root_info->hw_position[1] == 0xff)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "new tcam got no space for covered l0!!!\n");
        ret = CTC_E_NO_RESOURCE;
        goto error5;
    }

    CTC_ERROR_GOTO(_sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item_new->sram_idx, 1), ret, error5);

    g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][ip_ver]++;
    *pp_l0_item_new = p_l0_item_new;

    return ret;

error5:
    sys_nalpm_trie_delete (p_tcam_item_new->trie, key, p_l1_root_info->route_masklen, (trie_node_t **) &p_trie_l0_info, 0);
error4:
    if(p_trie_l0_info)
    {
        mem_free(p_trie_l0_info);
    }
error3:
    sys_nalpm_trie_destroy(p_l0_item_new->trie);
error2:
    sys_nalpm_trie_delete(prefix_trie, key, p_l1_root_info->tcam_masklen, (trie_node_t **)&p_trie_l0_item, 0);
error1:
    if (p_trie_l0_item)
    {
        mem_free(p_trie_l0_item);
    }
error0:
    if (p_l1_root_info)
    {
        mem_free(p_l1_root_info);
    }
    return ret;
}

int32
_sys_nalpm2_l0_process_cover(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param_new,
                             sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_tcam_item_t* p_tcam_item_new,
                             sys_nalpm2_cookie_t* p_cookie_l0, sys_nalpm2_cookie_t** pp_cookie_l1)
{
    sys_ipuc_param_t sys_ipuc_param_move;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_cover_trav_t trav_data;
    sys_nalpm2_l0_item_t* p_l0_item_new = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_covered = NULL;
    sys_ipuc_info_t* p_info_array[SYS_NALPM2_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4] = {NULL};  /* for pick covered route info */
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info_array[SYS_NALPM2_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4] = {NULL}; 
    sys_nalpm2_cookie_t* p_cookie = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_ipuc_info_t* p_best_route = NULL;
    uint32 key[4] = {0};
    int32 ret = 0;
    uint16 covered_route_num = 0;
    uint16 i = 0;
    uint16 sram_idx = 0;
    uint16 snake_idx = 0;
    uint16 entry_offset = 0;
    uint8 sub_bkt = 0;
    uint8 ip_ver = p_sys_ipuc_param_new->param.ip_ver;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    /*1. pick covered route in old trie  */
    sal_memset(&trav_data, 0, sizeof(sys_nalpm2_route_cover_trav_t));
    trav_data.ptr1 = p_info_array;
    trav_data.ptr2 = p_tcam_item_new;
    trav_data.value2 = lchip;
    /* 
        trav_data.ptr1 for picked ipuc_info array that covered
        trav_data.ptr2 for new tcam item for compare
        trav_data.ptr3 for l0 item which has covered route.Can't more than one!
        trav_data.value1 for covered_route_num
        trav_data.value2 for lchip
     */
    sys_nalpm_trie_traverse(p_tcam_item->trie->trie,
                           _sys_nalpm2_pick_covered_route, (void*)(&trav_data), _TRIE_INORDER_TRAVERSE);

    covered_route_num = trav_data.value1;
    if(!covered_route_num || trav_data.ptr3 == NULL)
    {
        return CTC_E_NONE;
    }
    p_l0_item_covered = trav_data.ptr3;

    ret = (_sys_nalpm2_sram_idx_alloc_l1(lchip, ip_ver, &sram_idx, &sub_bkt, 1));
    if(ret)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "NO resource for route cover!!\n");
        return ret;
    }

    sal_memset(&sys_ipuc_param_move, 0, sizeof(sys_ipuc_param_t));
    sal_memset(&lkp_rlt, 0, sizeof(sys_nalpm2_route_store_info_t));
    lkp_rlt.p_tcam_item = p_tcam_item_new;

    sys_ipuc_param_move.param.ip_ver = ip_ver;
    sys_ipuc_param_move.param.vrf_id = p_sys_ipuc_param_new->param.vrf_id;
    sal_memcpy(&sys_ipuc_param_move.param.ip, &p_tcam_item_new->p_l0_root_info->ip, IP_ADDR_SIZE(sys_ipuc_param_move.param.ip_ver));
    CTC_ERROR_RETURN(_sys_nalpm2_create_cookie_l1(lchip, p_l0_item_covered, p_l0_item_new, &p_cookie));

    /* add new L0 node */
    ret = _sys_nalpm2_add_covered_l0_node(lchip, &sys_ipuc_param_move, p_tcam_item_new, &p_l0_item_new, p_cookie_l0);
    if(!p_l0_item_new || ret)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "creat covered new l0 fail!!!!\n");
        mem_free(p_cookie);
        return ret;
    }
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).p_l0_item[sub_bkt] = p_l0_item_new;
    p_l0_item_new->sram_idx = sram_idx;
    p_l0_item_new->sub_bkt = sub_bkt;
    p_l1_root_info = p_l0_item_new->p_l1_root_info;
    snake_idx = p_l1_root_info->hw_position[0];
    entry_offset = p_l1_root_info->hw_position[1];
    p_tcam_item_new->p_l0_info_array[snake_idx][entry_offset] = p_l1_root_info;
    CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item_new->sram_idx).bitmap[snake_idx], entry_offset);
    p_l0_item_new->p_tcam_item = p_tcam_item_new;

    /* remove l1 node from old l0 */
    i = 0;
    do
    {
        sys_nalpm2_trie_l1_info_t* p_trie_l1_info = NULL;
        sal_memcpy(key, &p_info_array[i]->ip.ipv4, IP_ADDR_SIZE(ip_ver));
        SYS_IPV6_IP_SORT(ip_ver, key);

        /* 3.1 delete trie */
        ret = sys_nalpm_trie_delete(p_l0_item_covered->trie, key, p_info_array[i]->masklen, (trie_node_t**)&p_trie_l1_info, 1);
        if (ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "delete from old l1 error\n");
        }
        p_trie_l1_info_array[i] = p_trie_l1_info;
        if(p_trie_l1_info_array[i]->p_l1_info != p_info_array[i])
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Error happen when move l1 node,move info not in trie!!!\n");
        }

        if((!sal_memcmp(&p_info_array[i]->ip, &p_sys_ipuc_param_new->info->ip, IP_ADDR_SIZE(ip_ver))) &&
           (p_info_array[i]->masklen == p_sys_ipuc_param_new->info->masklen) &&
           (g_sys_nalpm2_master[lchip]->p_cookie_split_l1 &&
            p_l0_item_covered == g_sys_nalpm2_master[lchip]->p_cookie_split_l1->p_splited_l0 &&
            !g_sys_nalpm2_master[lchip]->p_cookie_split_l1->route_in_new_trie))
        {
            g_sys_nalpm2_master[lchip]->p_cookie_split_l1->new_route_moved = TRUE;
        }

        _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item_covered->sram_idx, -1);

        i++;
    }while(i < covered_route_num && p_info_array[i]);
    

    i = 0;
    do
    {
        sal_memcpy(key, &p_info_array[i]->ip.ipv4, IP_ADDR_SIZE(ip_ver));
        SYS_IPV6_IP_SORT(ip_ver, key);

        ret = sys_nalpm_trie_insert(p_l0_item_new->trie, key, NULL, p_info_array[i]->masklen, (trie_node_t *)p_trie_l1_info_array[i], 1);
        if (ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "reinsert l1 error\n");
        }
        _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item_new->sram_idx, 1);

        i++;
    }while(i < covered_route_num && p_info_array[i]);

    _sys_nalpm2_alloc_offset_array_l1(lchip, p_l0_item_new, p_cookie);
    _sys_nalpm2_renew_route_trie_l1(lchip, p_l0_item_new, p_cookie, 1);
    _sys_nalpm2_write_route_cookie_l1(lchip, NULL, p_l0_item_new, p_cookie);

    if(g_sys_nalpm2_master[lchip]->p_cookie_split_l1 &&
       p_l0_item_covered == g_sys_nalpm2_master[lchip]->p_cookie_split_l1->p_splited_l0)
    {
        sys_ipuc_info_t route_info_void;
        uint8 idx = 0;
        uint8 i = 0;
        uint8 j = 0;

        sal_memset(&route_info_void, 0, sizeof(sys_ipuc_info_t));

        /* 1. clear sram */
        idx = 0;
        do
        {
            if (!p_cookie->clear_cnt)
            {
                break;
            }
            i = (p_cookie->clear_array[idx] >> 8);
            j = (p_cookie->clear_array[idx] & 0xFF);
            p_l0_item_covered->p_l1_info_array[i][j] = NULL;
            CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item_covered->sram_idx).bitmap[i], j);
            _sys_nalpm2_write_sram_l1(lchip, p_l0_item_covered, &route_info_void, i, j, 0,
                                g_sys_nalpm2_master[lchip]->p_cookie_split_l1->ds_snake[i], g_sys_nalpm2_master[lchip]->p_cookie_split_l1->ds_snake_mask[i]);

            idx++;
        } while (idx < p_cookie->clear_cnt);
        p_cookie->need_free = 1;
        //mem_free(p_cookie); /* free it after write tcam */
    }
    else
    {
        _sys_nalpm2_renew_route_trie_l1(lchip, p_l0_item_covered, p_cookie, 0);
        _sys_nalpm2_reinstall_element_l1(lchip, p_l0_item_covered, p_cookie);
        p_cookie->p_splited_l0 = p_l0_item_covered;
        g_sys_nalpm2_master[lchip]->p_cookie_covered_l1 = p_cookie;/* free p_cookie outside*/
    }
    p_cookie->old_sram_idx_l1 = p_l0_item_covered->sram_idx;
    p_cookie->new_sram_idx_l1 = p_l0_item_new->sram_idx;
    *pp_cookie_l1 = p_cookie; /* return it out side for move hit */

    /* process L1 route cover */
    _sys_nalpm2_search_best_route_in_sram_l1(lchip, p_l0_item_covered, p_l1_root_info, &p_best_route);
    if(p_best_route)
    {
        p_l0_item_new->p_l1_root_AD = p_best_route;
        p_l1_root_info->ad_idx = p_best_route->ad_index;
        p_tcam_item_new->p_l0_root_AD = p_best_route;
        p_tcam_item_new->p_l0_root_info->ad_idx = p_best_route->ad_index;
    }
    else if(p_l0_item_covered->p_l1_root_AD)
    {
        p_l0_item_new->p_l1_root_AD = p_l0_item_covered->p_l1_root_AD;
        p_l1_root_info->ad_idx = p_l0_item_covered->p_l1_root_AD->ad_index;
        p_tcam_item_new->p_l0_root_AD = p_l0_item_covered->p_l1_root_AD;
        p_tcam_item_new->p_l0_root_info->ad_idx = p_l0_item_covered->p_l1_root_AD->ad_index;
    }
    else
    {
        p_l0_item_new->p_l1_root_AD = NULL;
        p_tcam_item_new->p_l0_root_AD = NULL;
        p_l1_root_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET_L0;
        p_tcam_item_new->p_l0_root_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    }
    /* return for update l1 route cover */
    g_sys_nalpm2_master[lchip]->p_cookie_split_l1->p_new_l0 = p_l0_item_new;

    _sys_nalpm2_write_sram_l0(lchip, p_tcam_item_new, p_l1_root_info, snake_idx, entry_offset, 0,
                                p_cookie_l0->ds_snake_new[snake_idx], p_cookie_l0->ds_snake_new_mask[snake_idx]);

    if(!p_l0_item_covered->trie->trie)
    {
        void *p_node1 = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][p_sys_ipuc_param_new->param.vrf_id]->trie, sys_nalpm2_trie_l0_item_t, node);
        void *p_node2 = CONTAINER_OF(p_l0_item_covered, sys_nalpm2_trie_l0_item_t, l0_item);

        /* 8.1 this node is not the root node */
        if (p_node1 != p_node2)
        {
            sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
            sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
            sys_nalpm2_info_t *p_l1_root_info = NULL;
            sys_nalpm2_info_tmp_t route_info_void2;
            sys_nalpm2_info_t* route_info_void = (sys_nalpm2_info_t*)&route_info_void2;
            uint8 i,j;

            /* 8.1.0 prepare data */
            sal_memset(key, 0, sizeof(key));
            p_l1_root_info = p_l0_item_covered->p_l1_root_info;
            i = p_l1_root_info->hw_position[0];
            j = p_l1_root_info->hw_position[1];

            /* 8.1.0.1 level1 sram root needs convert!!! */
            if (p_l1_root_info->tcam_masklen)
            {
                sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
                SYS_IPV6_IP_SORT(ip_ver, key);
            }

            sys_nalpm_trie_delete(p_tcam_item->trie, key, p_l1_root_info->tcam_masklen, (trie_node_t **) &p_trie_l0_info, 1);
            if(p_trie_l0_info)
            {
                mem_free(p_trie_l0_info);
            }
            sys_nalpm_trie_destroy(p_l0_item_covered->trie);

            sal_memset(key, 0, sizeof(key));
            if (p_l1_root_info->tcam_masklen)
            {
                sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
                SYS_IPV6_IP_SORT(ip_ver, key);
            }
            /* 8.1.3 delete l0 item from trie */
            sys_nalpm_trie_delete(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][p_sys_ipuc_param_new->param.vrf_id],
                                                    key, p_l1_root_info->tcam_masklen, (trie_node_t**)&p_trie_l0_item, 1);

            _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, -1);
            _sys_nalpm2_sram_idx_free_l1(lchip, p_l0_item_covered->sram_idx, ip_ver);
            /* 8.1.5 free memory */
            if(p_trie_l0_item)
            {
                mem_free(p_trie_l0_item->l0_item.p_l1_root_info);
                p_trie_l0_item->l0_item.p_l1_root_info = NULL;
                mem_free(p_trie_l0_item);/*p_l0_item_covered is free*/
            }

            sal_memset(&route_info_void2, 0, sizeof(sys_nalpm2_info_tmp_t));
            p_tcam_item->p_l0_info_array[i][j] = NULL;
            CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);
            _sys_nalpm2_write_sram_l0(lchip, p_tcam_item, route_info_void, i, j, 0, p_cookie_l0->ds_snake[i], p_cookie_l0->ds_snake_mask[i]);
            g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][ip_ver]--;
            if(g_sys_nalpm2_master[lchip]->p_cookie_split_l1 &&
               p_l0_item_covered == g_sys_nalpm2_master[lchip]->p_cookie_split_l1->p_splited_l0)
            {
                g_sys_nalpm2_master[lchip]->p_cookie_split_l1->p_splited_l0 = NULL;
            }
            else
            {
                //mem_free(g_sys_nalpm2_master[lchip]->p_cookie_covered_l1);
                p_cookie->need_free = 1;
                g_sys_nalpm2_master[lchip]->p_cookie_covered_l1 = NULL;
            }
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_move_hit(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_l0_item_t* p_l0_item_new, sys_nalpm2_cookie_t* p_cookie)
{
    uint8 i  = 0;
    uint8 j = 0;
    uint8 new_i = 0;
    uint8 new_j = 0;
    uint8 idx = 0;
    uint8 hit = 0;
    uint8 domain_type = 0;
    uint8 old_domain_type = 0;
    uint16 old_sram_idx = 0;
    uint16 new_sram_idx = 0;
    uint32 hw_idx = 0;
    uint32 old_hw_idx = 0;

    old_sram_idx = p_l0_item ? p_l0_item->sram_idx : p_cookie->old_sram_idx_l1;
    new_sram_idx = p_l0_item_new ? p_l0_item_new->sram_idx : p_cookie->new_sram_idx_l1;
    for (idx = 0; idx < p_cookie->clear_cnt; idx++)
    {
        /* get old hit */
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx]& 0xFF);

        old_hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, old_sram_idx, i);
        old_domain_type = i >= NALPM2_BUKCET_SNACK_PER_GRP_L1(lchip) ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 : SYS_AGING_DOMAIN_LPM_HASH_GROUP0;
        MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(old_domain_type,SYS_AGING_PP_EN_BIT):old_domain_type;
        MCHIP_LA(lchip)->get_aging_status(lchip, old_domain_type, ((LEVEL1 << 30) | (j << 24) | old_hw_idx), &hit);

        /* Set new hit if hit was set */
        if(hit)
        {
            new_i = (p_cookie->index_array[idx] >> 8);
            new_j = (p_cookie->index_array[idx] & 0xFF);

            hw_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, new_sram_idx, new_i);
            domain_type = new_i >= NALPM2_BUKCET_SNACK_PER_GRP_L1(lchip) ? SYS_AGING_DOMAIN_LPM_HASH_GROUP1 : SYS_AGING_DOMAIN_LPM_HASH_GROUP0;
            MCHIP_FEATURE_PP_EN(lchip, CTC_FEATURE_IPUC)?CTC_BIT_SET(domain_type,SYS_AGING_PP_EN_BIT):domain_type;
            MCHIP_LA(lchip)->set_aging_status(lchip, domain_type, ((LEVEL1 << 30) | (new_j << 24) | hw_idx), 0, 1);
            MCHIP_LA(lchip)->set_aging_status(lchip, old_domain_type, ((LEVEL1 << 30) | (j << 24) | old_hw_idx), 0, 0);
        }
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_add_split_l0(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item, sys_ipuc_param_t* p_sys_ipuc_param,
                                sys_nalpm2_l0_item_t* p_l0_item, sys_nalpm2_tcam_item_t** pp_new_tcam_item)
{
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item2 = NULL;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item_new = NULL;
    sys_nalpm2_info_t* p_l0_info_new = NULL;
    sys_nalpm2_info_t* p_l0_root_info= NULL;
    sys_nalpm2_cookie_t* p_cookie = NULL;
    sys_nalpm2_cookie_t* p_cookie_covered_l1 = NULL;
    trie_node_t* split_trie_root = NULL;
    trie_t *prefix_trie = NULL;
    trie_t *clone_trie = NULL;
    sys_nalpm2_info_t* p_l0_info_array_bak[SYS_NALPM2_MAX_SNACKE_L0][ROUTE_NUM_PER_SNAKE_V4_L0];
    int32 ret = CTC_E_NONE;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    uint32 max_split_len = 0;
    uint32 split_pfx[4] = {0};
    uint32 pfx_len = 0;
    uint16 sram_idx = 0;
    uint16 vrf_id = 0;
    uint8 max_split_cnt = SYS_NALPM2_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4;
    uint8 route_in_new_trie = 0;
    uint8 sub_bkt = 0;
    uint8 ip_ver = 0;
    uint8 fmt = 0;
    uint8 idx = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;
    fmt = NALPM2_FORMAT(lchip, ip_ver);

    p_l0_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_l0_root_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        return ret;
    }
    sal_memset(p_l0_root_info, 0, NALPM2_INFO_SIZE(ip_ver));

    p_trie_tcam_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_tcam_item_t), sys_nalpm2_trie_tcam_item_t);
    if(NULL == p_trie_tcam_item)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error1;
    }
    sal_memset(p_trie_tcam_item, 0, sizeof(sys_nalpm2_trie_tcam_item_t));

    /* 1. alloc sram index */
    CTC_ERROR_GOTO(_sys_nalpm2_sram_idx_alloc_l0(lchip, ip_ver, &sram_idx, &sub_bkt, 0), ret, error2);

    /* 2. backup */
    /* 2.1 backup trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_clone(p_tcam_item->trie, &clone_trie), ret, error3);
    sal_memcpy(p_l0_info_array_bak, p_tcam_item->p_l0_info_array, (sizeof(sys_nalpm2_info_t*) * SYS_NALPM2_MAX_SNACKE_L0 * ROUTE_NUM_PER_SNAKE_V4_L0));
    /* 3. split trie(software) */
    /* 3.0 split trie */
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    max_split_len = ((ip_ver == CTC_IP_VER_4) ? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX);
    max_split_cnt = ((NALPM2_BUCKET_FMT_MAX_L0(lchip, fmt) - NALPM2_BUCKET_USE_CNT_L0(lchip, sram_idx)));
    CTC_ERROR_GOTO(sys_nalpm_trie_split(p_tcam_item->trie, max_split_len, FALSE, split_pfx, &pfx_len, &split_trie_root, NULL, FALSE, max_split_cnt),ret,error4);

    /* 3.1 create root of new trie */
    /* 3.1.1 create route info */
    sal_memset(p_l0_root_info->ip, 0, IP_ADDR_SIZE(ip_ver));
    SYS_NALPM_CONVERT_TO_MSB(split_pfx, pfx_len, p_l0_root_info->ip, ip_ver);
    SYS_IPV6_IP_SORT(ip_ver, p_l0_root_info->ip);
    p_l0_root_info->tcam_masklen = pfx_len;
    p_l0_root_info->ip_ver = ip_ver;
    p_l0_root_info->vrf_id = vrf_id;

    /* 3.1.2 create tcam item */
    p_tcam_item_new = &p_trie_tcam_item->tcam_item;
    p_tcam_item_new->p_l0_root_info = p_l0_root_info;

    CTC_ERROR_GOTO(_sys_nalpm2_tcam_idx_alloc(lchip, p_ipuc_param, p_tcam_item_new), ret, error4);

    p_tcam_item_new->sram_type = p_tcam_item->sram_type;
    p_tcam_item_new->sram_idx = sram_idx;
    p_tcam_item_new->sub_bkt = sub_bkt;
    NALPM2_BUCKET_ARRAY_L0(lchip, sram_idx).p_tcam_item[sub_bkt] = p_tcam_item_new;

    /* 3.2 init new trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(max_split_len, &(p_tcam_item_new->trie)),ret, error5);
    p_tcam_item_new->trie->trie = split_trie_root;

    /* 3.3 add new tcam pfx to prefix trie*/
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, split_pfx, NULL, pfx_len, (trie_node_t *)p_trie_tcam_item, 0), ret, error6);

    /* 4. split bucket(hardware sram) */
    /* 4.1 prepare cookie data */
    _sys_nalpm2_create_cookie_l0(lchip, p_tcam_item, p_tcam_item_new, &p_cookie);

    /* 4.2 alloc new trie offset */
    _sys_nalpm2_alloc_offset_array_l0(lchip, p_tcam_item_new, p_cookie);

    /* 4.3 establish new tree sram & add new route in new tree (DB) */
    CTC_ERROR_GOTO(_sys_nalpm2_renew_route_trie_l0(lchip, p_tcam_item_new, p_cookie, 1),ret , error7);

    /* 4.4 clear sram of old tree splited tree & add new route to old tree (DB) */
    CTC_ERROR_GOTO(_sys_nalpm2_renew_route_trie_l0(lchip, p_tcam_item, p_cookie, 0), ret, error7);
    _sys_nalpm2_reinstall_element_l0(lchip, p_tcam_item, p_cookie);

    /* 4.5 set backup info */
    route_in_new_trie = p_cookie->route_in_new_trie;
    p_l0_info_new = p_cookie->p_l0_info_new;

    /* 4.6 update bucket list */
    _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, -split_trie_root->count + 1);
    _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item_new->sram_idx, split_trie_root->count);

    /* 5. link tcam item & l0 item */
    if (p_l0_item)
    {
        p_l0_item->p_tcam_item = route_in_new_trie ? p_tcam_item_new : p_tcam_item;
        p_l0_info_new->p_l0_item = p_l0_item;
    }

    p_trie_tcam_item2 = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie, sys_nalpm2_trie_tcam_item_t, node);
    CTC_ERROR_GOTO(_sys_nalpm2_read_tcam(lchip, &p_trie_tcam_item2->tcam_item, &ad_idx), ret, error8);

    /* 6.5.3 add covered route to new tcam item */
    _sys_nalpm2_find_best_covered_node_l0_2(lchip, p_tcam_item_new, ad_idx);

    /* proccess covered route in old tcam*/
    if(_sys_nalpm2_need_proccess_route_cover(lchip, p_tcam_item_new))
    {
        CTC_ERROR_GOTO(_sys_nalpm2_l0_process_cover(lchip, p_sys_ipuc_param, p_tcam_item, p_tcam_item_new, p_cookie, &p_cookie_covered_l1), ret, error8);
    }

    /* 7. write sram(L1 write sram func must before "L0 process func")
        (p_tcam_item may be freed becuase the new route needs to do route cover and is moved to new position[_sys_nalpm2_move_route_trie].
        Thus the address of p_tcam_item may be used by other memory) */
    _sys_nalpm2_write_route_cookie_l0(lchip, NULL, p_tcam_item_new, p_cookie);

    /* 8. install to tcam */
    CTC_ERROR_GOTO(_sys_nalpm2_write_tcam(lchip, p_tcam_item_new, DO_ADD, 0), ret, error9);

    if(p_cookie_covered_l1 && g_sys_nalpm2_master[lchip]->move_hit_en)
    {
        _sys_nalpm2_move_hit(lchip, NULL, NULL, p_cookie_covered_l1);
    }

    /* clear old sram after flow change */
    _sys_nalpm2_write_route_cookie_l0(lchip, p_tcam_item, NULL, p_cookie);

    /* 9. free memory */
    sys_nalpm_trie_clear(clone_trie->trie);
    sys_nalpm_trie_destroy(clone_trie);
    if (p_cookie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "mem_free(p_cookie)!!!\n");
        mem_free(p_cookie);
        p_cookie = NULL;
    }

    if(p_cookie_covered_l1 && p_cookie_covered_l1->need_free)
    {
        mem_free(p_cookie_covered_l1);
    }

    return ret;

error9:
    {
        /* callback hash problem -- sram hardware can not callback!!! */
        sys_nalpm2_info_tmp_t route_info_void2;
        sys_nalpm2_info_t* route_info_void = (sys_nalpm2_info_t*)&route_info_void2;

        /* clear sram */
        sal_memset(&route_info_void2, 0, sizeof(sys_nalpm2_info_tmp_t));
        route_info_void->ip_ver = ip_ver;

        CTC_ERROR_RETURN(_sys_nalpm2_write_sram_l0(lchip, p_tcam_item, route_info_void, p_l0_info_new->hw_position[0], p_l0_info_new->hw_position[1], 0,
                         route_in_new_trie ? p_cookie->ds_snake_new[p_l0_info_new->hw_position[0]] : p_cookie->ds_snake[p_l0_info_new->hw_position[1]],
                         route_in_new_trie ? p_cookie->ds_snake_new_mask[p_l0_info_new->hw_position[0]] : p_cookie->ds_snake_mask[p_l0_info_new->hw_position[1]]));

        _sys_nalpm2_write_route_cookie_l0(lchip, p_tcam_item, p_tcam_item_new, p_cookie);
    }
    if(p_cookie_covered_l1 && p_cookie_covered_l1->need_free)
    {
        mem_free(p_cookie_covered_l1);
    }
error8:
    _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item_new->sram_idx, -split_trie_root->count);
    _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, split_trie_root->count - 1);
    do
    {
        uint8 i = 0;
        uint8 j = 0;
        if (!p_cookie->clear_cnt)
        {
            break;
        }
        i = (p_cookie->clear_array[idx] >> 8);
        j = (p_cookie->clear_array[idx] & 0xFF);
        p_tcam_item->p_l0_info_array[i][j] = p_l0_info_array_bak[i][j];
        p_tcam_item->p_l0_info_array[i][j]->p_l0_item->p_tcam_item = p_tcam_item;
        p_tcam_item->p_l0_info_array[i][j]->hw_position[0] = i;
        p_tcam_item->p_l0_info_array[i][j]->hw_position[1] = j;
        CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[i], j);

        idx++;
    } while (idx < p_cookie->clear_cnt);
error7:
    if (p_cookie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "mem_free(p_cookie)!!!\n");
        mem_free(p_cookie);
        p_cookie = NULL;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "_sys_nalpm2_ln_insert fail!!!\n");
    sys_nalpm_trie_delete (prefix_trie, split_pfx, pfx_len, (trie_node_t**)&p_trie_tcam_item, 0);
error6:
    sys_nalpm_trie_destroy((p_tcam_item_new->trie));
error5:
    _sys_nalpm2_tcam_idx_free(lchip, p_ipuc_param, p_tcam_item_new);
error4:
    sys_nalpm_trie_clear(p_tcam_item->trie->trie);
    sys_nalpm_trie_clear(split_trie_root);   /* double free here!!!! */
    sys_nalpm_trie_destroy(p_tcam_item->trie);
    p_tcam_item->trie = clone_trie;
error3:
    _sys_nalpm2_sram_idx_free_l0(lchip, sram_idx, ip_ver);
error2:
    if (p_trie_tcam_item)
    {
        mem_free(p_trie_tcam_item);
    }
error1:
    if(p_l0_root_info)
    {
        mem_free(p_l0_root_info);
    }

    return ret;
}

int32
_sys_nalpm2_add_split_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item, sys_ipuc_param_t* p_sys_ipuc_param,
                                sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_l0_item_t** pp_l0_item_new)
{
    sys_ipuc_info_t* p_l1_info_array2[SYS_NALPM2_MAX_SNAKE][ROUTE_NUM_PER_SNAKE_V4] = {{NULL}};
    sys_ipuc_info_t* p_l1_info_array[SYS_NALPM2_MAX_SNAKE][ROUTE_NUM_PER_SNAKE_V4] = {{NULL}};
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_new = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_ipuc_info_t* p_l1_info_new = NULL;
    sys_ipuc_info_t* p_best_route = NULL;
    sys_nalpm2_cookie_t* p_cookie = NULL;
    trie_node_t* split_trie_root = NULL;
    trie_t *prefix_trie = NULL;
    trie_t *clone_trie = NULL;
    uint8 bitmap_root[SYS_NALPM2_MAX_SNAKE];
    uint8 bitmap_new[SYS_NALPM2_MAX_SNAKE];
    int32 ret = CTC_E_NONE;
    uint32 ad_idx = INVALID_DRV_NEXTHOP_OFFSET;
    uint32 max_split_len = 0;
    uint32 split_pfx[4] = {0};
    uint32 pfx_len = 0;
    uint16 sram_idx = 0;
    uint16 vrf_id = 0;
    uint16 db_size = 0;
    uint8 max_split_cnt = SYS_NALPM2_MAX_SNAKE*ROUTE_NUM_PER_SNAKE_V4;
    uint8 route_in_new_trie = 0;
    uint8 sram_type = 0;
    uint8 i = 0, j = 0;
    uint8 sub_bkt = 0;
    uint8 ip_ver = 0;
    uint8 fmt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;
    sram_type = p_l0_item->sram_type;
    fmt = NALPM2_FORMAT(lchip, ip_ver);
    db_size = IPUC_INFO_SIZE(ip_ver);

    i = 0;
    do
    {
        j = 0;
        do
        {
            p_l1_info_array[i][j] = mem_malloc(MEM_IPUC_MODULE, db_size);
            if (NULL == p_l1_info_array[i][j])
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                ret = CTC_E_NO_MEMORY;
                goto error0;
            }
            sal_memset(p_l1_info_array[i][j], 0, db_size);

            j++;

        } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    p_l1_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_l1_root_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }
    sal_memset(p_l1_root_info, 0, NALPM2_INFO_SIZE(ip_ver));

    p_trie_l0_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_item_t), sys_nalpm2_trie_l0_item_t);
    if(NULL == p_trie_l0_item)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error1;
    }
    sal_memset(p_trie_l0_item, 0, sizeof(sys_nalpm2_trie_l0_item_t));

    /* 1. alloc sram index */
    CTC_ERROR_GOTO(_sys_nalpm2_sram_idx_alloc_l1(lchip, ip_ver, &sram_idx, &sub_bkt, 0), ret, error2);

    /* 2. backup */
    /* 2.1 backup trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_clone(p_l0_item->trie, &clone_trie), ret, error3);

    /* 2.2 backup bitmap & info array */
    sal_memcpy(bitmap_root, NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap, sizeof(bitmap_root));
    sal_memcpy(bitmap_new, NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap, sizeof(bitmap_new));

    /* 2.2.1 backup pointer */
    sal_memcpy(p_l1_info_array2, p_l0_item->p_l1_info_array, sizeof(sys_ipuc_info_t*) * SYS_NALPM2_MAX_SNAKE * ROUTE_NUM_PER_SNAKE_V4);

    /* 2.2.1 backup memory */
    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_l0_item->p_l1_info_array[i][j])
            {
                j++;
                continue;
            }
            sal_memcpy(p_l1_info_array[i][j], p_l0_item->p_l1_info_array[i][j], db_size);

            j++;

        } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    /* 3. split trie(software) */
    /* 3.0 split trie */
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    max_split_len = ((ip_ver == CTC_IP_VER_4) ? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX);
    max_split_cnt = ((NALPM2_BUCKET_FMT_MAX_L1(lchip, fmt) - NALPM2_BUCKET_USE_CNT_L1(lchip, sram_idx)));
    CTC_ERROR_GOTO(sys_nalpm_trie_split(p_l0_item->trie, max_split_len, FALSE, split_pfx, &pfx_len, &split_trie_root, NULL, FALSE, max_split_cnt),ret,error3_1);

    /* 3.1 create root of new trie */
    /* 3.1.1 create route info */
    sal_memset(p_l1_root_info->ip, 0, IP_ADDR_SIZE(ip_ver));
    SYS_NALPM_CONVERT_TO_MSB(split_pfx, pfx_len, p_l1_root_info->ip, ip_ver);
    SYS_IPV6_IP_SORT(ip_ver, p_l1_root_info->ip);
    p_l1_root_info->tcam_masklen = pfx_len;
    p_l1_root_info->ip_ver = ip_ver;
    p_l1_root_info->vrf_id = vrf_id;

    /* 3.1.2 create l0 item */
    p_l0_item_new = &p_trie_l0_item->l0_item;
    p_l0_item_new->p_l1_root_info = p_l1_root_info;

    if (p_l0_item->sram_type == SYS_NALPM2_SRAM_TYPE_V6_128)
    {
        p_l0_item_new->sram_type = SYS_NALPM2_SRAM_TYPE_V6_128;
    }
    else
    {
        p_l0_item_new->sram_type = p_l0_item->sram_type;
    }
    p_l0_item_new->sram_idx = sram_idx;
    p_l0_item_new->sub_bkt = sub_bkt;
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).p_l0_item[sub_bkt] = p_l0_item_new;

    /* 3.2 init new trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(max_split_len, &(p_l0_item_new->trie)),ret, error4);
    p_l0_item_new->trie->trie = split_trie_root;

    /* 4. split bucket(hardware sram) */
    /* 4.1 prepare cookie data */
    _sys_nalpm2_create_cookie_l1(lchip, p_l0_item, p_l0_item_new, &p_cookie);

    /* 4.2 alloc new trie offset */
    _sys_nalpm2_alloc_offset_array_l1(lchip, p_l0_item_new, p_cookie);

    /* 4.3 establish new tree sram & add new route in new tree (DB) */
    CTC_ERROR_GOTO(_sys_nalpm2_renew_route_trie_l1(lchip, p_l0_item_new, p_cookie, 1),ret , error6);

    /* 4.4 clear sram of old tree splited tree & add new route to old tree (DB) */
    CTC_ERROR_GOTO(_sys_nalpm2_renew_route_trie_l1(lchip, p_l0_item, p_cookie, 0), ret, error6);
    _sys_nalpm2_reinstall_element_l1(lchip, p_l0_item, p_cookie);

    /* 4.5 set backup info */
    route_in_new_trie = p_cookie->route_in_new_trie;
    p_l1_info_new = p_cookie->p_l1_info_new;

    /* 4.6 update bucket list */
    _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item->sram_idx, -split_trie_root->count + 1);
    _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item_new->sram_idx, split_trie_root->count);

    /* 5. check whether needs do route cover */
    CTC_ERROR_GOTO(_sys_nalpm2_search_best_route_in_sram_l1(lchip, p_l0_item, p_l0_item_new->p_l1_root_info, &p_best_route), ret, error7);

    if (p_best_route)
    {
        p_l0_item_new->p_l1_root_info->ad_idx = p_best_route->ad_index;
        p_l0_item_new->p_l1_root_AD = p_best_route;
    }
    else
    {
        p_trie_tcam_item = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie, sys_nalpm2_trie_tcam_item_t, node);
        CTC_ERROR_GOTO(_sys_nalpm2_read_tcam(lchip, &p_trie_tcam_item->tcam_item, &ad_idx), ret, error7);
        p_l0_item_new->p_l1_root_info->ad_idx = ad_idx;/* 0x3FFF??? */
    }

    /* 6. write sram(L1 write sram func must before "L0 process func")
        (p_l0_item may be freed becuase the new route needs to do route cover and is moved to new position[_sys_nalpm2_move_route_trie].
        Thus the address of p_l0_item may be used by other memory) */
    _sys_nalpm2_write_route_cookie_l1(lchip, NULL, p_l0_item_new, p_cookie);

    /* 7. continue to insert level1 root info to level0 (L0 process func) */
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, split_pfx, NULL, pfx_len, (trie_node_t *)p_trie_l0_item, 0), ret, error8);

    /* 7.1 backup recursion state */
    p_cookie->p_splited_l0 = p_l0_item;
    g_sys_nalpm2_master[lchip]->p_cookie_split_l1 = p_cookie;
    CTC_ERROR_GOTO(_sys_nalpm2_ln_insert_l0(lchip, p_sys_ipuc_param, p_tcam_item, p_l0_item_new, 0), ret, error9);

    /* clear old sram after flow change */
    if(p_cookie->p_splited_l0)
    {
        if(g_sys_nalpm2_master[lchip]->move_hit_en)
        {
            _sys_nalpm2_move_hit(lchip, p_l0_item, p_l0_item_new, p_cookie);
        }
        _sys_nalpm2_write_route_cookie_l1(lchip, p_l0_item, NULL, p_cookie);
    }

    if(g_sys_nalpm2_master[lchip]->p_cookie_covered_l1)
    {
        /* new l1 has wirten inside _sys_nalpm2_l0_process_cover()*/
        _sys_nalpm2_write_route_cookie_l1(lchip, g_sys_nalpm2_master[lchip]->p_cookie_covered_l1->p_splited_l0, NULL, 
                                                 g_sys_nalpm2_master[lchip]->p_cookie_covered_l1);
        mem_free(g_sys_nalpm2_master[lchip]->p_cookie_covered_l1);
        g_sys_nalpm2_master[lchip]->p_cookie_covered_l1 = NULL;
    }

    /* 8. set output data */
    if (route_in_new_trie)
    {
        p_sys_ipuc_param->info->sram_idx = p_l0_item_new->sram_idx;
        p_sys_ipuc_param->info->sub_bkt = p_l0_item_new->sub_bkt;
        *pp_l0_item_new = p_l0_item_new;
    }
    else
    {
        if(p_cookie->p_splited_l0)
        {
            if(!p_cookie->new_route_moved)
            {
                p_sys_ipuc_param->info->sram_idx = p_l0_item->sram_idx;
                p_sys_ipuc_param->info->sub_bkt = p_l0_item->sub_bkt;
                *pp_l0_item_new = p_l0_item;
            }
            else
            {
                *pp_l0_item_new = p_cookie->p_new_l0;
            }
            
        }
        else
        {
            *pp_l0_item_new = NULL;
        }
    }

    /* 9. free memory */
    i = 0;
    do
    {
        j = 0;
        do
        {
            mem_free(p_l1_info_array[i][j]);
            p_l1_info_array[i][j] = NULL;

            j++;

        } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));
    sys_nalpm_trie_clear(clone_trie->trie);
    sys_nalpm_trie_destroy(clone_trie);
    if (p_cookie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "mem_free(p_cookie)!!!\n");
        mem_free(p_cookie);
        p_cookie = NULL;
        g_sys_nalpm2_master[lchip]->p_cookie_split_l1 = NULL;
    }
    return ret;

error9:
    if(g_sys_nalpm2_master[lchip]->p_cookie_covered_l1)
    {
        mem_free(g_sys_nalpm2_master[lchip]->p_cookie_covered_l1);
        g_sys_nalpm2_master[lchip]->p_cookie_covered_l1 = NULL;
    }
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "_sys_nalpm2_ln_insert fail!!!\n");
    sys_nalpm_trie_delete (prefix_trie, split_pfx, pfx_len, (trie_node_t **)&p_trie_l0_item, 0);
error8:
    {
        sys_ipuc_info_t route_info_void;

        /* clear sram */
        sal_memset(&route_info_void, 0, sizeof(sys_ipuc_info_t));

        _sys_nalpm2_write_sram_l1(lchip, p_l0_item, &route_info_void, p_l1_info_new->snake_idx, p_l1_info_new->entry_offset, 0,
                                 route_in_new_trie ? p_cookie->ds_snake_new[p_l1_info_new->snake_idx] : p_cookie->ds_snake[p_l1_info_new->snake_idx],
                                 route_in_new_trie ? p_cookie->ds_snake_new_mask[p_l1_info_new->snake_idx] : p_cookie->ds_snake_mask[p_l1_info_new->snake_idx]);

        /* call back backup cookie sram ??? */
        i = 0;
        do
        {
            j = 0;
            do
            {
                if (NULL == p_l0_item_new->p_l1_info_array[i][j])
                {
                    j++;
                    continue;
                }
                _sys_nalpm2_write_sram_l1(lchip, p_l0_item_new, &route_info_void, i, j, 0,
                                 p_cookie->ds_snake_new[i],
                                 p_cookie->ds_snake_new_mask[i]);

                j++;

            } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

            i++;

        } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));
        _sys_nalpm2_write_sram_l1(lchip, p_l0_item_new, &route_info_void, i, j, 0,
                                 p_cookie->ds_snake_new[i],
                                 p_cookie->ds_snake_new_mask[i]);

        _sys_nalpm2_write_route_cookie_l1(lchip, NULL, p_l0_item_new, p_cookie);
    }
error7:
    /* update bucket */
    _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item_new->sram_idx, -split_trie_root->count);
    _sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item->sram_idx, split_trie_root->count - 1);
error6:
    if (p_cookie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "mem_free(p_cookie)!!!\n");
        mem_free(p_cookie);
        p_cookie = NULL;
        g_sys_nalpm2_master[lchip]->p_cookie_split_l1 = NULL;
    }
    sys_nalpm_trie_destroy((p_l0_item_new->trie));
error4:
    sal_memcpy(NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).bitmap, bitmap_root, sizeof(bitmap_root));
    sal_memcpy(NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap, bitmap_new, sizeof(bitmap_new));
    sal_memcpy(p_l0_item->p_l1_info_array,p_l1_info_array2, sizeof(sys_ipuc_info_t*) * SYS_NALPM2_MAX_SNAKE * ROUTE_NUM_PER_SNAKE_V4);
    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_l1_info_array2[i][j])
            {
                j++;
                continue;
            }
            sal_memcpy(p_l0_item->p_l1_info_array[i][j], p_l1_info_array[i][j], db_size);

            j++;

        } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));
    sys_nalpm_trie_clear(split_trie_root);
error3_1:
    sys_nalpm_trie_clear(p_l0_item->trie->trie);
    sys_nalpm_trie_destroy(p_l0_item->trie);
    p_l0_item->trie = clone_trie;
error3:
    _sys_nalpm2_sram_idx_free_l1(lchip, sram_idx, ip_ver);
error2:
    if (p_trie_l0_item)
    {
        mem_free(p_trie_l0_item);
    }
error1:
    if(p_l1_root_info)
    {
        mem_free(p_l1_root_info);
    }
error0:
    i = 0;
    do
    {
        j = 0;
        do
        {
            if (p_l1_info_array[i][j])
            {
                mem_free(p_l1_info_array[i][j]);
            }

            j++;

        } while (j < _sys_nalpm2_get_snake_route_num_l1(lchip, sram_type));

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return ret;
}

int32
_sys_nalpm2_ln_insert_l0(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_l0_item_t *p_l0_item, uint8 new_root)
{
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_info_t* p_l0_info = NULL;
    int32 ret = CTC_E_NONE;
    uint32 key[4] = {0};
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    p_trie_l0_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_info_t), sys_nalpm2_trie_l0_info_t);
    if (NULL == p_trie_l0_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_trie_l0_info, 0 , sizeof(sys_nalpm2_trie_l0_info_t));

    /* 0.1 L0 route info is L1 root */
    p_l0_info = p_l0_item->p_l1_root_info;
    ip_ver = p_l0_info->ip_ver;

    if (p_l0_info->tcam_masklen)
    {
        SYS_NALPM2_IP_ADDR_MASK(p_l0_info->ip, p_l0_info->tcam_masklen, ip_ver)
    }

    if (p_l0_item->p_l1_root_AD)
    {
        p_l0_info->ad_idx = p_l0_item->p_l1_root_AD->ad_index;
    }
    else
    {
        p_l0_info->ad_idx = INVALID_DRV_NEXTHOP_OFFSET_L0; /*invalid nexthop*/
    }
    p_l0_info->route_masklen = p_l0_info->tcam_masklen;

    /* 1. lookup sw node */
    sal_memset(p_lkp_rlt, 0 , sizeof(sys_nalpm2_route_store_info_t));
    p_lkp_rlt->p_tcam_item = p_tcam_item;
    CTC_ERROR_GOTO(_sys_nalpm2_route_lkp_l0(lchip, p_l0_info, p_lkp_rlt), ret, error1);
    p_tcam_item = p_lkp_rlt->p_tcam_item;
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "insert LEVEL0, lookup tcam_idx:%d, sram_idx:%d\n", p_tcam_item->tcam_idx, p_tcam_item->sram_idx);

    /* 2. create soft table */
    p_trie_l0_info->p_l0_info = p_l0_info;
    p_l0_info->p_l0_item = p_l0_item;

    if (p_tcam_item->sram_type == SYS_NALPM2_SRAM_TYPE_VOID)
    {
        _sys_nalpm2_set_sram_type_l0(lchip, p_l0_info->ip_ver, p_l0_info->route_masklen, p_tcam_item);
    }

    /* 3. create trie */
    sal_memcpy(key, p_l0_info->ip, IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key);

    ret = sys_nalpm_trie_insert(p_tcam_item->trie, key, NULL, p_l0_info->route_masklen, (trie_node_t *)p_trie_l0_info, 1);
    if (CTC_E_NONE != ret)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "!!!trie_insert failed: %d\r\n", ret);
        goto error1;
    }

    /* 4. wheather need split */
    if (!_sys_nalpm2_sram_entry_is_full_l0(lchip, p_tcam_item, new_root))
    {
        CTC_ERROR_GOTO(_sys_nalpm2_add_directly_l0(lchip, p_tcam_item, p_l0_info, p_lkp_rlt), ret, error2);

        /* 4.1 L0 item -> tcam item */
        p_l0_item->p_tcam_item = p_tcam_item;

        /* 4.2 update bucket */
        CTC_ERROR_GOTO(_sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, 1), ret, error2)

    }
    else
    {
        p_l0_info->hw_position[0] = 0xff;
        p_l0_info->hw_position[1] = 0xff;
        CTC_ERROR_GOTO(_sys_nalpm2_add_split_l0(lchip, p_tcam_item, p_sys_ipuc_param, p_l0_item, NULL), ret, error2);
    }

    g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][ip_ver]++;

    return ret;

error2:
    sys_nalpm_trie_delete (p_tcam_item->trie, key, p_l0_info->route_masklen, (trie_node_t **) &p_trie_l0_info, 0);
error1:
    if(p_trie_l0_info)
        mem_free(p_trie_l0_info);

    return ret;
}

int32
_sys_nalpm2_ln_del_l0(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, sys_nalpm2_tcam_item_t* p_tcam_item, sys_nalpm2_l0_item_t* p_l0_item, uint8 is_inner)
{
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_info_t* p_l0_info = NULL;
    uint32 key[4] = {0};
    int32 ret = CTC_E_NONE;
    uint32 pfx_len = 0;
    uint16 vrf_id = 0;
    uint8 entry_offset = 0;
    uint8 snake_idx = 0;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    /* 0.1 L0 route info is L1 root */
    p_l0_info = p_l0_item->p_l1_root_info;

    entry_offset = p_l0_info->hw_position[1];
    snake_idx = p_l0_info->hw_position[0];
    pfx_len = p_l0_info->route_masklen;
    ip_ver = p_l0_info->ip_ver;
    vrf_id = p_l0_info->vrf_id;

    sal_memcpy(key, p_l0_info->ip, IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key);

    /* 1. destroy trie */
    CTC_ERROR_RETURN(sys_nalpm_trie_delete(p_tcam_item->trie, key, pfx_len, (trie_node_t **) &p_trie_l0_info, 1));
    //mem_free(p_trie_l0_info->p_l0_info);
    mem_free(p_trie_l0_info);

    /* 2. clear sram */
    if (!is_inner)
    {
        sys_nalpm2_info_tmp_t route_info_void2;
        sys_nalpm2_info_t* route_info_void = (sys_nalpm2_info_t*)&route_info_void2;

        sal_memset(&route_info_void2, 0, sizeof(sys_nalpm2_info_tmp_t));
        route_info_void->ip_ver = ip_ver;

        CTC_ERROR_RETURN(_sys_nalpm2_write_sram_l0(lchip, p_tcam_item, route_info_void, snake_idx, entry_offset, 0, NULL, NULL));
    }
    p_tcam_item->p_l0_info_array[snake_idx][entry_offset] = NULL;

    /* 3. update bucket */
    CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[snake_idx], entry_offset);
    CTC_ERROR_RETURN(_sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, -1));

    /* 4. sram entry is empty, release tcam*/
    if (!p_tcam_item->trie->trie)
    {
        void *p_node1 = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie, sys_nalpm2_trie_tcam_item_t, node);
        void *p_node2 = CONTAINER_OF(p_tcam_item, sys_nalpm2_trie_tcam_item_t, tcam_item);

        if(p_node1 != p_node2)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)  sram entry is empty, release tcam\n",__LINE__);

            /* 4.0 prepare data */
            sal_memset(key, 0 , sizeof(key));
            sal_memcpy(key, p_tcam_item->p_l0_root_info->ip, IP_ADDR_SIZE(ip_ver));
            SYS_IPV6_IP_SORT(ip_ver, key);
            SYS_NALPM_CONVERT_TO_LSB(key, p_tcam_item->p_l0_root_info->tcam_masklen, ip_ver);

            /* 4.1 destroy trie */
            CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_tcam_item->trie));

            /* 4.2 delete tcam item from trie */
            CTC_ERROR_RETURN(sys_nalpm_trie_delete(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id],
                                            key, p_tcam_item->p_l0_root_info->tcam_masklen, (trie_node_t**)&p_trie_tcam_item, 0));

            /* 4.3 delete tcam */
            CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, p_tcam_item, DO_DEL, 0));

            /* 4.4 free tcam index */
            CTC_ERROR_RETURN(_sys_nalpm2_tcam_idx_free(lchip, p_ipuc_param, p_tcam_item));

            /* 4.5 free level0 sram index */
            CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free_l0(lchip, p_tcam_item->sram_idx, ip_ver));

            /* 4.6 free memory */
            mem_free(p_trie_tcam_item->tcam_item.p_l0_root_info);
            mem_free(p_trie_tcam_item);
        }
    }
    g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][ip_ver]--;

    return ret;
}

int32
_sys_nalpm2_create_node_l1(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_route_store_info_t *p_lkp_rlt)
{
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    trie_t *prefix_trie = NULL;
    int32 ret = CTC_E_NONE;
    uint32 key[4] = {0};
    uint16 sram_idx = 0;
    uint8 sub_bkt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. apply for memory */
    p_l1_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(p_ipuc_param->ip_ver), sys_nalpm2_info_t);
    if (NULL == p_l1_root_info)
    {
        return CTC_E_NO_MEMORY;
    }

    p_trie_l0_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_item_t), sys_nalpm2_trie_l0_item_t);
    if(NULL == p_trie_l0_item)
    {
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }

    sal_memset(p_l1_root_info, 0, NALPM2_INFO_SIZE(p_ipuc_param->ip_ver));
    sal_memset(p_trie_l0_item, 0, sizeof(sys_nalpm2_trie_l0_item_t));

    /* 1. prepare data */
    p_l0_item = &p_trie_l0_item->l0_item;
    p_l0_item->p_l1_root_info = p_l1_root_info;
    p_l1_root_info->vrf_id = p_ipuc_param->vrf_id;
    p_l1_root_info->ip_ver = p_ipuc_param->ip_ver;
    p_l1_root_info->tcam_masklen = p_lkp_rlt->p_tcam_item->p_l0_root_info->tcam_masklen;/* Tcam common prefix len */
    p_l1_root_info->route_masklen = p_l1_root_info->tcam_masklen;
    sal_memcpy(p_l1_root_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(p_ipuc_param->ip_ver));
    sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(p_ipuc_param->ip_ver));
    SYS_IPV6_IP_SORT(p_ipuc_param->ip_ver, key);
    SYS_NALPM_CONVERT_TO_LSB(key, p_l1_root_info->tcam_masklen, p_ipuc_param->ip_ver);

    /* 2. alloc sram index */
    CTC_ERROR_GOTO(_sys_nalpm2_sram_idx_alloc_l1(lchip, p_ipuc_param->ip_ver, &sram_idx, &sub_bkt, 0), ret, error1);
    NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).p_l0_item[sub_bkt] = NULL;
    p_l0_item->sram_idx = sram_idx;
    p_l0_item->sub_bkt = sub_bkt;

    /* 3. set sram type */
    if (p_l0_item->sram_type == SYS_NALPM2_SRAM_TYPE_VOID)
    {
        _sys_nalpm2_set_sram_type_l1(lchip, p_ipuc_param->ip_ver, p_ipuc_param->masklen, p_l0_item);
    }

    /* 4. insert level1 trie */
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_l1_root_info->ip_ver][p_l1_root_info->vrf_id];
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(prefix_trie, key, NULL, p_l1_root_info->tcam_masklen, (trie_node_t *)p_trie_l0_item, 0), ret, error2);

    /* 5. init route trie */
    CTC_ERROR_GOTO(sys_nalpm_trie_init(
                  ((CTC_IP_VER_4 == p_ipuc_param->ip_ver) ? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX), &p_l0_item->trie), ret, error3);

    /* 6. insert level1 node */ /* independent Function */ /* TODO */
    CTC_ERROR_GOTO(_sys_nalpm2_ln_insert_l0(lchip, p_sys_ipuc_param, p_tcam_item, p_l0_item, 1), ret, error4);
    p_lkp_rlt->p_l0_item = p_l0_item;

    return ret;

error4:
    sys_nalpm_trie_destroy(p_l0_item->trie);
error3:
    sys_nalpm_trie_delete(prefix_trie, key, p_l1_root_info->tcam_masklen, (trie_node_t **)&p_trie_l0_item, 0);
error2:
    _sys_nalpm2_sram_idx_free_l1(lchip, sram_idx, p_ipuc_param->ip_ver);
error1:
    if (p_trie_l0_item)
    {
        mem_free(p_trie_l0_item);
    }
error0:
    if (p_l1_root_info)
    {
        mem_free(p_l1_root_info);
    }
    return ret;
}

int32
_sys_nalpm2_destroy_node_l1(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_route_store_info_t *p_lkp_rlt)
{
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_info_t* p_nalpm_info = NULL;
    trie_t *prefix_trie = NULL;
    uint32 key[4] = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(p_ipuc_param->ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_nalpm_info, 0, (NALPM2_INFO_SIZE(p_ipuc_param->ip_ver)));
    p_nalpm_info->ip_ver = p_ipuc_param->ip_ver;
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(p_ipuc_param->ip_ver));

    /* 1. delete level0 node */
    CTC_ERROR_RETURN(_sys_nalpm2_ln_del_l0(lchip, p_ipuc_param, p_lkp_rlt->p_tcam_item, p_lkp_rlt->p_l0_item, 0));

    /* 2. free sram index */
    CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free_l1(lchip, p_lkp_rlt->p_l0_item->sram_idx, p_ipuc_param->ip_ver));

    /* 3. destroy route trie */
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_lkp_rlt->p_l0_item->trie));

    /* 4. delete LEVEL1 trie node */
    sal_memcpy(key, p_nalpm_info->ip, IP_ADDR_SIZE(p_ipuc_param->ip_ver));
    SYS_IPV6_IP_SORT(p_ipuc_param->ip_ver, key);
    SYS_NALPM_CONVERT_TO_LSB(key, p_lkp_rlt->p_l0_item->p_l1_root_info->tcam_masklen, p_ipuc_param->ip_ver);

    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_ipuc_param->ip_ver][p_ipuc_param->vrf_id];
    CTC_ERROR_RETURN(sys_nalpm_trie_delete(prefix_trie, key, p_lkp_rlt->p_l0_item->p_l1_root_info->tcam_masklen, (trie_node_t **)&p_trie_l0_item, 0));

    /* 5. free memory */
    mem_free(p_trie_l0_item->l0_item.p_l1_root_info);
    mem_free(p_trie_l0_item);
    mem_free(p_nalpm_info);

    return CTC_E_NONE;
}

int32
_sys_nalpm2_find_best_covered_node_l0(uint8 lchip, sys_nalpm2_route_store_info_t *p_lkp_rlt)
{
    sys_nalpm2_tcam_item_t* p_tcam_item_temp;
    uint8 best_snake = 0xff, best_offset = 0xff;
    uint8 route_per_snake = 0;
    uint8 i = 0, j = 0;

    p_tcam_item_temp = p_lkp_rlt->p_l0_item->p_tcam_item;
    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item_temp->sram_type);

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_tcam_item_temp->p_l0_info_array[i][j])
            {
                j++;
                continue;
            }

            if (NULL == p_tcam_item_temp->p_l0_info_array[i][j]->p_l0_item)
            {
                j++;
                continue;
            }

            if (NULL == p_tcam_item_temp->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD)
            {
                j++;
                continue;
            }

            if (p_lkp_rlt->p_l0_item->p_l1_root_info->tcam_masklen <=
                p_tcam_item_temp->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD->masklen)
            {
                j++;
                continue;
            }

            if (0xff == best_snake)
            {
                best_snake = i;
                best_offset = j;
            }

            if (p_tcam_item_temp->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD->masklen >
                p_tcam_item_temp->p_l0_info_array[best_snake][best_offset]->p_l0_item->p_l1_root_AD->masklen)
            {
                best_snake = i;
                best_offset = j;
            }

            j++;

        } while (j < route_per_snake);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    if (best_snake != 0xff)
    {
        p_lkp_rlt->p_l0_item->p_l1_root_AD = p_tcam_item_temp->p_l0_info_array[best_snake][best_offset]->p_l0_item->p_l1_root_AD;
        p_lkp_rlt->p_l0_item->p_l1_root_info->ad_idx = p_lkp_rlt->p_l0_item->p_l1_root_AD->ad_index;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_find_best_covered_node_l0_2(uint8 lchip, sys_nalpm2_tcam_item_t* p_tcam_item_new, uint32 ad_idx)
{
    uint8 best_snake = 0xff, best_offset = 0xff;
    uint8 route_per_snake = 0;
    uint8 i = 0, j = 0;

    route_per_snake = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item_new->sram_type);

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_tcam_item_new->p_l0_info_array[i][j])
            {
                j++;
                continue;
            }

            if (NULL == p_tcam_item_new->p_l0_info_array[i][j]->p_l0_item)
            {
                j++;
                continue;
            }

            if (NULL == p_tcam_item_new->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD)
            {
                j++;
                continue;
            }

            if (p_tcam_item_new->p_l0_root_info->tcam_masklen <=
                p_tcam_item_new->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD->masklen)
            {
                j++;
                continue;
            }

            if (0xff == best_snake)
            {
                best_snake = i;
                best_offset = j;
            }

            if (p_tcam_item_new->p_l0_info_array[i][j]->p_l0_item->p_l1_root_AD->masklen >
                p_tcam_item_new->p_l0_info_array[best_snake][best_offset]->p_l0_item->p_l1_root_AD->masklen)
            {
                best_snake = i;
                best_offset = j;
            }

            j++;

        } while (j < route_per_snake);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    if (best_snake != 0xff)
    {
        p_tcam_item_new->p_l0_root_AD = p_tcam_item_new->p_l0_info_array[best_snake][best_offset]->p_l0_item->p_l1_root_AD;
        p_tcam_item_new->p_l0_root_info->ad_idx = p_tcam_item_new->p_l0_root_AD->ad_index;
    }
    else
    {
        p_tcam_item_new->p_l0_root_info->ad_idx = ad_idx;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_route_vrf_init(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param)
{
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    CTC_ERROR_GOTO(_sys_nalpm2_ln_pivot_insert_l0(lchip, p_sys_ipuc_param, &p_tcam_item), ret, error0);
    CTC_ERROR_GOTO(_sys_nalpm2_ln_pivot_insert_l1(lchip, p_sys_ipuc_param, &p_l0_item), ret, error1);

    _sys_nalpm2_clear_snake_l0(lchip, p_tcam_item);
    _sys_nalpm2_clear_snake_l1(lchip, p_l0_item);

    CTC_ERROR_GOTO(_sys_nalpm2_ln_insert_l0(lchip, p_sys_ipuc_param, p_tcam_item, p_l0_item, 0), ret, error2);
    CTC_ERROR_GOTO(_sys_nalpm2_write_tcam(lchip, p_tcam_item, DO_ADD, 0), ret, error3);

    p_l0_item->p_tcam_item = p_tcam_item;

#ifdef IPUC_TEST_STUB
    /*add to prefix trie*/
    sys_nalpm_trie_init ((CTC_IP_VER_4 == p_sys_ipuc_param->param.ip_ver )? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX,
                                    &(g_sys_nalpm2_master[lchip]->route_db_trie[p_sys_ipuc_param->param.ip_ver][p_sys_ipuc_param->param.vrf_id]));
#endif
    return ret;

error3:
    _sys_nalpm2_ln_del_l0(lchip, &p_sys_ipuc_param->param, p_tcam_item, p_l0_item, 0);
error2:
    _sys_nalpm2_ln_pivot_del_l1(lchip, p_sys_ipuc_param);
error1:
    _sys_nalpm2_ln_pivot_del_l0(lchip, p_sys_ipuc_param);
error0:
    return ret;
}

int32
_sys_nalpm2_route_vrf_deinit(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param)
{
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_trie_tcam_item_t * p_trie_tcam_item = NULL;
    sys_nalpm2_trie_l0_item_t * p_trie_l0_item = NULL;
    trie_t* prefix_trie;
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    uint8  ip_ver = 0;
    uint16 vrf_id = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_USW_REGISTER_WB_SYNC_EN(lchip, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1, 1);
    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    /* 0.1 level0 */
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id];
    p_trie_tcam_item = CONTAINER_OF(prefix_trie->trie, sys_nalpm2_trie_tcam_item_t, node);
    p_tcam_item = &p_trie_tcam_item->tcam_item;

    /* 0.2 level1 */
    prefix_trie = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id];
    p_trie_l0_item = CONTAINER_OF(prefix_trie->trie, sys_nalpm2_trie_l0_item_t, node);
    p_l0_item = &p_trie_l0_item->l0_item;

    /* 1. delete tcam */
    _sys_nalpm2_write_tcam(lchip, p_tcam_item, DO_DEL, 0);

    /* 2. delete level0/level1 sram */
    _sys_nalpm2_ln_del_l0(lchip, p_ipuc_param, p_tcam_item, p_l0_item, 0);
    _sys_nalpm2_ln_pivot_del_l0(lchip, p_sys_ipuc_param);
    _sys_nalpm2_ln_pivot_del_l1(lchip, p_sys_ipuc_param);

#ifdef IPUC_TEST_STUB
    CTC_ERROR_RETURN(sys_nalpm_trie_destroy(g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][vrf_id]));
    g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][vrf_id] = NULL;

#endif

    return CTC_E_NONE;
}

#define _________API_________

int32
sys_nalpm2_init(uint8 lchip, ctc_ipuc_global_cfg_t* p_ipuc_global_cfg, uint8 ipsa_enable)
{
    uint32 lpm_pipeline_if_ctl[4/4] = {0};
    uint16 vrfid_num[MAX_CTC_IP_VER] = {0};
    uint32 value = 0;
    uint32 cmd = 0;
    uint16 i = 0, j = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (g_sys_nalpm2_master[lchip])
    {
        CTC_ERROR_RETURN(sys_nalpm2_deinit(lchip));
    }

    if(p_ipuc_global_cfg->master_lchip_valid && p_ipuc_global_cfg->master_lchip != lchip)
    {
        if(!g_sys_nalpm2_master[p_ipuc_global_cfg->master_lchip])
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, " Master lchip must init first!! \n");
            return CTC_E_NOT_READY;
        }
        g_sys_nalpm2_master[lchip] = g_sys_nalpm2_master[p_ipuc_global_cfg->master_lchip];
        return CTC_E_NONE;
    }

    g_sys_nalpm2_master[lchip] = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_master_t), sys_nalpm2_master_t);
    if(NULL == g_sys_nalpm2_master[lchip])
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(g_sys_nalpm2_master[lchip], 0, sizeof(sys_nalpm2_master_t));

    g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL0] = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_nalpm2_ipuc_hash_make_l0,
                            (hash_cmp_fn)_sys_nalpm2_ipuc_hash_cmp_l0);

    g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL1] = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_nalpm2_ipuc_hash_make_l1,
                            (hash_cmp_fn)_sys_nalpm2_ipuc_hash_cmp_l1);


    g_sys_nalpm2_master[lchip]->pivot_hash[LEVEL0] = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_nalpm2_pivot_hash_make_l0,
                            (hash_cmp_fn)_sys_nalpm2_pivot_hash_cmp_l0);

    g_sys_nalpm2_master[lchip]->pivot_hash[LEVEL1] = ctc_hash_create(1,
                            (IPUC_IPV6_HASH_MASK + 1),
                            (hash_key_fn)_sys_nalpm2_pivot_hash_make_l1,
                            (hash_cmp_fn)_sys_nalpm2_pivot_hash_cmp_l1);

    g_sys_nalpm2_master[lchip]->split_mode = 1;
    g_sys_nalpm2_master[lchip]->bucket_num = 4;
    g_sys_nalpm2_master[lchip]->frag_arrange_enable = 0;
    g_sys_nalpm2_master[lchip]->ipsa_enable = ipsa_enable;
    g_sys_nalpm2_master[lchip]->use_snake64 = (p_ipuc_global_cfg->prefix64_mode == CTC_IPUC_SHORT_V6_PREFIX_MODE ||
                                              p_ipuc_global_cfg->prefix64_mode == 3);

    vrfid_num[CTC_IP_VER_4] = MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID) + 1;
    vrfid_num[CTC_IP_VER_6] = MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID) + 1;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "vrfid_num v4 [%u], v6 [%u]\n",vrfid_num[CTC_IP_VER_4], vrfid_num[CTC_IP_VER_6]);

    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4], trie_t);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6], trie_t);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4], trie_t);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6], trie_t);
    g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4] = mem_malloc2(MEM_IPUC_MODULE, sizeof(uint32) * vrfid_num[CTC_IP_VER_4], uint32);
    g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6] = mem_malloc2(MEM_IPUC_MODULE, sizeof(uint32) * vrfid_num[CTC_IP_VER_6], uint32);

    if (!g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4] || !g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6] ||
        !g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4] || !g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6] ||
        !g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4] || !g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6])
    {
        goto error0;
    }

    sal_memset(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4]);
    sal_memset(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6]);
    sal_memset(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4]);
    sal_memset(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6], 0, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6]);
    sal_memset(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4], 0, sizeof(uint32) * vrfid_num[CTC_IP_VER_4]);
    sal_memset(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6], 0, sizeof(uint32) * vrfid_num[CTC_IP_VER_6]);

    CTC_ERROR_RETURN(sys_usw_opf_init(lchip, &g_sys_nalpm2_master[lchip]->opf_type_nalpm, 2, "opf-type-nalpm"));
    CTC_ERROR_RETURN(_sys_nalpm2_bucket_init_l0(lchip));
    CTC_ERROR_RETURN(_sys_nalpm2_bucket_init_l1(lchip));

    for (i = 0; i <= SYS_NALPM2_V4_MASK_LEN_MAX; i++)
    {
        for (j = 0; j < i; j++)
        {
            g_sys_nalpm2_master[lchip]->len2pfx[i] |= 1 << (SYS_NALPM2_V4_MASK_LEN_MAX - 1 - j);
        }
    }

#ifdef IPUC_TEST_STUB
    g_sys_nalpm2_master[lchip]->route_db_trie[CTC_IP_VER_4] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_4], trie_t );
    g_sys_nalpm2_master[lchip]->route_db_trie[CTC_IP_VER_6] = mem_malloc2(MEM_IPUC_MODULE, sizeof(trie_t *) * vrfid_num[CTC_IP_VER_6], trie_t );
#endif

    g_sys_nalpm2_master[lchip]->build_l1_snake_cb[SYS_NALPM2_SRAM_TYPE_V4_32] = _sys_nalpm2_build_snake_ipv4_32_l1;
    g_sys_nalpm2_master[lchip]->build_l1_snake_cb[SYS_NALPM2_SRAM_TYPE_V6_64] = _sys_nalpm2_build_snake_ipv6_64_l1;
    g_sys_nalpm2_master[lchip]->build_l1_snake_cb[SYS_NALPM2_SRAM_TYPE_V6_128] = _sys_nalpm2_build_snake_ipv6_128_l1;
    g_sys_nalpm2_master[lchip]->move_hit_en = 1;

    cmd = DRV_IOR(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), lpm_pipeline_if_ctl));
    value = 1;
    SetLpmPipelineIfCtl(V,neoLpmEn_f,lpm_pipeline_if_ctl, value);
    cmd = DRV_IOW(LpmPipelineIfCtl_t, DRV_ENTRY_FLAG);
    CTC_ERROR_RETURN(DRV_IOCTL(lchip, 0, DRV_CMD_BMP_EN(cmd, MCHIP_FEATURE_PP_EN(lchip,CTC_FEATURE_IPUC)), lpm_pipeline_if_ctl));

    return CTC_E_NONE;

error0:
    if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4])
    {
        mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4]);
    }
    if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6])
    {
        mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6]);
    }
    if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4])
    {
        mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4]);
    }
    if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6])
    {
        mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6]);
    }
    if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4])
    {
        mem_free(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4]);
    }
    if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6])
    {
        mem_free(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6]);
    }
    if (g_sys_nalpm2_master[lchip])
    {
        mem_free(g_sys_nalpm2_master[lchip]);
    }
    return CTC_E_NO_MEMORY;
}

int32
sys_nalpm2_deinit(uint8 lchip)
{
    uint8 ip_ver = 0;
    uint16 vrfid = 0;

    if(NULL == g_sys_nalpm2_master[lchip])
    {
        return CTC_E_NONE;
    }
    if(p_usw_ipuc_master[lchip]->master_lchip != lchip)
    {
        g_sys_nalpm2_master[lchip] = NULL;
        return CTC_E_NONE;
    }

    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        for (vrfid = 0; vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); vrfid++)
        {
            if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid] == NULL)
            {
                continue;
            }
            sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie, _sys_nalpm2_free_prefix_node_l0, NULL, _TRIE_POSTORDER_TRAVERSE);
            mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]);
        }
    }

    for (ip_ver = CTC_IP_VER_4; ip_ver < MAX_CTC_IP_VER; ip_ver++)
    {
        for (vrfid = 0; vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); vrfid++)
        {
            if (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid] == NULL)
            {
                continue;
            }
            sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]->trie, _sys_nalpm2_free_prefix_node_l1, NULL, _TRIE_POSTORDER_TRAVERSE);
            mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]);
        }
    }

    CTC_ERROR_RETURN(_sys_nalpm2_bucket_deinit_l0(lchip));
    CTC_ERROR_RETURN(_sys_nalpm2_bucket_deinit_l1(lchip));

    mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_4]);
    mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][CTC_IP_VER_6]);
    mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_4]);
    mem_free(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6]);
    mem_free(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4]);
    mem_free(g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6]);

    sys_usw_opf_deinit(lchip, g_sys_nalpm2_master[lchip]->opf_type_nalpm);

    ctc_hash_free(g_sys_nalpm2_master[lchip]->pivot_hash[LEVEL0]);
    ctc_hash_free(g_sys_nalpm2_master[lchip]->pivot_hash[LEVEL1]);
    ctc_hash_free(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL0]);
    ctc_hash_free(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL1]);

    mem_free(g_sys_nalpm2_master[lchip]);

    return CTC_E_NONE;
}

int32
sys_nalpm2_add(uint8 lchip, void* p_sys_ipuc_param_v, uint32 ad_index, void* data)
{
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_new = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_info_t* p_nalpm_info = NULL;
    uint32 key[4] = {0};
    int32 ret = CTC_E_NONE;
    uint16 vrf_id = p_ipuc_param->vrf_id;
    uint8 ip_ver = p_ipuc_param->ip_ver;
    uint8 create_new_node = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (p_ipuc_param->masklen > 64 &&  p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] == 0 &&
        p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_PUB] == 0)
    {
        return CTC_E_INVALID_PARAM;
    }

    /* 0. prepare data */
    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_nalpm_info, 0, (NALPM2_INFO_SIZE(ip_ver)));

    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    p_nalpm_info->ad_idx = ad_index;
    p_nalpm_info->ip_ver = ip_ver;

    /* 1. warmboot or add lpm route */
    if (CTC_WB_ENABLE(lchip) && CTC_WB_STATUS(lchip) == CTC_WB_STATUS_RELOADING)
    {
        CTC_ERROR_GOTO(_sys_nalpm2_wb_restore_l0(lchip, p_sys_ipuc_param, p_nalpm_info), ret, error1);
    }
    else
    {
        /* 1.1 init vrf memory and default route */
        if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][p_nalpm_info->vrf_id] == 0)
        {
            CTC_ERROR_GOTO(_sys_nalpm2_route_vrf_init(lchip, p_sys_ipuc_param), ret, error1);
        }

        /* 1.2 update default route ad index */
        if(p_ipuc_param->masklen == 0)
        {
            CTC_ERROR_GOTO(sys_nalpm2_update(lchip, p_sys_ipuc_param, ad_index),ret, error1);
            g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][p_nalpm_info->vrf_id]++;
            mem_free(p_nalpm_info);
            return ret;
        }

        /* 1.3 lookup sw node */
        sal_memset(p_lkp_rlt, 0 , sizeof(sys_nalpm2_route_store_info_t));
        CTC_ERROR_GOTO(_sys_nalpm2_route_lkp_l0(lchip, p_nalpm_info, p_lkp_rlt), ret, error1);
        if (!p_lkp_rlt->tcam_hit || p_lkp_rlt->p_tcam_item == NULL)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- tcam not hit\r\n", __LINE__);
            ret =  CTC_E_NOT_EXIST;
            goto error1;
        }
        if (p_lkp_rlt->sram_hit[LEVEL1])
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sram hit\r\n", __LINE__);
            ret =  CTC_E_EXIST;
            goto error1;
        }

        /* 1.4 create new level1 PREFIX node(level0 node) if do not find level1 prefix node in level0 trie */
        if (!p_lkp_rlt->p_l0_item)
        {
            sys_ipuc_info_t ipuc_info_temp;

            /* 1.4.0 prepare data */
            sal_memset(&ipuc_info_temp, 0, sizeof(sys_ipuc_info_t));

            if (p_nalpm_info->ip_ver == CTC_IP_VER_6)
            {
                CTC_SET_FLAG(ipuc_info_temp.route_flag, SYS_IPUC_FLAG_IS_IPV6);
            }
            ipuc_info_temp.masklen = p_nalpm_info->route_masklen;
            ipuc_info_temp.vrf_id = p_nalpm_info->vrf_id;
            sal_memcpy(&(ipuc_info_temp.ip), p_nalpm_info->ip, IP_ADDR_SIZE(p_nalpm_info->ip_ver));

            /* 1.4.1 create level1 node */
            CTC_ERROR_GOTO(_sys_nalpm2_create_node_l1(lchip, p_sys_ipuc_param, p_lkp_rlt), ret, error1);
            create_new_node = 1;

            /* 1.4.2 find level1 node route cover */
            _sys_nalpm2_find_best_covered_node_l0(lchip, p_lkp_rlt);

            /* 1.4.3 alloc route(Level 1) snake_idx & entry_offset otherwise the snake_idx & entry_offset will be zero,
                which will lead to cover old position ([0, 0]) when alloc sub bucket */
            _sys_nalpm2_lkup_entry_l1(lchip, &ipuc_info_temp, p_lkp_rlt, p_lkp_rlt->p_l0_item);
        }

        p_l0_item = p_lkp_rlt->p_l0_item;
        p_l0_item_new = p_lkp_rlt->p_l0_item;

        /* 1.5 check and set sram type */
        if (p_l0_item->sram_type == SYS_NALPM2_SRAM_TYPE_V6_64 && p_nalpm_info->route_masklen > 64)
        {
            goto error2;
        }
        if (p_l0_item->sram_type == SYS_NALPM2_SRAM_TYPE_VOID)
        {
            _sys_nalpm2_set_sram_type_l1(lchip, p_nalpm_info->ip_ver, p_nalpm_info->route_masklen, p_l0_item);
        }

        /* 1.6 should not split tree when arrange fragment, this will lead to use more tcam resource */
        if(_sys_nalpm2_sram_entry_is_full_l1(lchip, p_l0_item) && (uint8*)data)
        {
            ret = CTC_E_NOT_SUPPORT;
            goto error2;
        }

        /* 1.7 insert route node in level1 prefix node */
        p_trie_l1_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l1_info_t), sys_nalpm2_trie_l1_info_t);
        if (NULL == p_trie_l1_info)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            ret = CTC_E_NO_MEMORY;
            goto error2;
        }
        sal_memset(p_trie_l1_info, 0, sizeof(sys_nalpm2_trie_l1_info_t));
        sal_memcpy(key, p_nalpm_info->ip, IP_ADDR_SIZE(p_nalpm_info->ip_ver));
        SYS_IPV6_IP_SORT(p_nalpm_info->ip_ver, key);
        p_trie_l1_info->p_l1_info = p_sys_ipuc_param->info;

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_INFO, "(%d)  p_trie_l1_info=[%p],p_nalpm_info=[%p], ip_ver[%u]\n", __LINE__, p_trie_l1_info, p_nalpm_info, p_nalpm_info->ip_ver);

        ret = sys_nalpm_trie_insert(p_l0_item->trie, key, NULL, p_nalpm_info->route_masklen, (trie_node_t *)p_trie_l1_info, 1);
        if (CTC_E_NONE != ret)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "!!!trie_insert failed: %d\r\n", ret);
            goto error3;
        }

        /* 1.8 check whether split trie set and set route info into hw */
        if (!_sys_nalpm2_sram_entry_is_full_l1(lchip, p_l0_item))
        {
            CTC_ERROR_GOTO(_sys_nalpm2_add_directly_l1(lchip, p_l0_item, p_sys_ipuc_param->info, p_lkp_rlt), ret, error4);

            /*update bucket*/
            CTC_ERROR_GOTO(_sys_nalpm2_bucket_list_update_l1(lchip, p_l0_item->sram_idx, 1), ret, error4);

            p_sys_ipuc_param->info->sram_idx = p_l0_item->sram_idx;
            p_sys_ipuc_param->info->sub_bkt= p_l0_item->sub_bkt;
        }
        else
        {
            p_nalpm_info->hw_position[0] = 0xff;
            p_nalpm_info->hw_position[1] = 0xff;
            p_sys_ipuc_param->info->snake_idx = 0xff;
            p_sys_ipuc_param->info->entry_offset = 0xff;
            CTC_ERROR_GOTO(_sys_nalpm2_add_split_l1(lchip, p_l0_item, p_sys_ipuc_param, p_lkp_rlt->p_tcam_item, &p_l0_item_new), ret, error4);
        }

        /* 1.9 set TCAM & L0 SRAM router cover and set/get TCAM & L0 SRAM aging bit */
        if (p_l0_item_new)
        {
            trie_node_t *node;
            uint32 key1[4] = {0};

            sal_memcpy(key1, p_l0_item_new->p_l1_root_info->ip, IP_ADDR_SIZE(p_nalpm_info->ip_ver));
            SYS_IPV6_IP_SORT(p_nalpm_info->ip_ver, key1);
            SYS_NALPM_CONVERT_TO_LSB(key1, p_l0_item_new->p_l1_root_info->tcam_masklen, p_nalpm_info->ip_ver);

            CTC_ERROR_RETURN(sys_nalpm_trie_find_lpm(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][p_nalpm_info->ip_ver][p_nalpm_info->vrf_id],
                                                     key1, p_l0_item_new->p_l1_root_info->tcam_masklen, &node, 0));

            ret = _sys_nalpm2_add_route_cover(lchip, p_l0_item_new, p_trie_l1_info->p_l1_info, p_sys_ipuc_param->param.nh_id, node->total_skip_len, 0, NULL);
            if (ret < 0)
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                return ret;
            }
        }

        /* 1.10 update stats */
        g_sys_nalpm2_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]++;
        g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
        g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL1][ip_ver]++;
    }

    if(p_nalpm_info)
    {
        mem_free(p_nalpm_info);
    }

#ifdef IPUC_TEST_STUB
    {
        sys_nalpm2_trie_l1_info_t* p_route_db_payload = NULL;
        p_route_db_payload = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l1_info_t), sys_nalpm2_trie_l1_info_t);
        sal_memset(p_route_db_payload, 0 , sizeof(sys_nalpm2_trie_l1_info_t));
        p_route_db_payload->p_l1_info = p_sys_ipuc_param->info;
        sal_memcpy(key, &p_sys_ipuc_param->info->ip, IP_ADDR_SIZE(ip_ver));
        SYS_IPV6_IP_SORT(ip_ver, key);
        sys_nalpm_trie_insert (g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][p_sys_ipuc_param->info->vrf_id],
                               key, NULL, p_ipuc_param->masklen, (trie_node_t *) p_route_db_payload, 1);
    }
#endif

    return ret;

error4:
    sys_nalpm_trie_delete(p_l0_item->trie, key, p_nalpm_info->route_masklen, (trie_node_t **) &p_trie_l1_info, 0);
error3:
    if(p_trie_l1_info)
    {
        mem_free(p_trie_l1_info);
    }
error2:
    if (create_new_node)
    {
        _sys_nalpm2_destroy_node_l1(lchip, p_sys_ipuc_param, p_lkp_rlt); //>>>>>>
    }
error1:
    if(p_nalpm_info)
    {
        mem_free(p_nalpm_info);
    }
    return ret;
}

int32
sys_nalpm2_del(uint8 lchip, void* p_sys_ipuc_param_v, void *p_lkp_rlt_inner)
{
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t* p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info = NULL;
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = NULL;
    sys_nalpm2_info_t* p_nalpm_info = NULL;
    int32 ret = CTC_E_NONE;
    uint32 key[4] = {0};
    uint32 pfx_len = 0;
    uint16 vrf_id = 0;
    uint8 is_inner = 0;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;
    vrf_id = p_ipuc_param->vrf_id;

    /* 1. update default route ad index be 0x3FFFF */
    if(p_ipuc_param->masklen== 0)
    {
        /* 1.1 update default route ad index be 0x3FFFF */
        if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][p_ipuc_param->vrf_id])
        {
            return CTC_E_NOT_EXIST;
        }
        CTC_ERROR_RETURN(sys_nalpm2_update( lchip, p_sys_ipuc_param, INVALID_DRV_NEXTHOP_OFFSET));
        g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]--;

        /* 1.2 deinit vrf */
        if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0)
        {
            CTC_ERROR_RETURN(_sys_nalpm2_route_vrf_deinit(lchip, p_sys_ipuc_param));
        }
        return ret;
    }

    /* 2. lookup sw node */
    /* 2.1 Used for outer */
    if (!p_lkp_rlt_inner)
    {
        /* 2.1.1 prepare data */
        p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
        if(NULL == p_nalpm_info)
        {
            return CTC_E_NO_MEMORY;
        }

        sal_memset(p_nalpm_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));
        sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
        p_nalpm_info->route_masklen = p_ipuc_param->masklen;
        p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
        p_nalpm_info->ip_ver = ip_ver;

        /* 2.1.2 lookup route */
        ret = _sys_nalpm2_route_lkp_l1(lchip, p_nalpm_info, p_lkp_rlt);

        mem_free(p_nalpm_info);

        if(ret < 0 || !p_lkp_rlt->sram_hit[LEVEL1])
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "can't find route\n");
            return CTC_E_NOT_EXIST;
        }
    }
    /* 2.1 Used for inner */
    else
    {
        sal_memcpy(p_lkp_rlt, (sys_nalpm2_route_store_info_t *)p_lkp_rlt_inner, sizeof(sys_nalpm2_route_store_info_t));
        is_inner = 1;
    }

    /* 3. del route */
    /* 3.0 prepare data */
    sal_memcpy(key, &p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]]->ip.ipv4, IP_ADDR_SIZE(ip_ver));
    pfx_len = p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]]->masklen;
    SYS_IPV6_IP_SORT(ip_ver, key);

    /* 3.1 delete trie */
    CTC_ERROR_RETURN(sys_nalpm_trie_delete(p_lkp_rlt->p_l0_item->trie, key, pfx_len, (trie_node_t**)&p_trie_l1_info, 1));

#ifdef IPUC_TEST_STUB
    {
        sys_nalpm2_trie_l1_info_t* p_route_db_payload = NULL;
        sal_memcpy(key, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
        sys_nalpm_trie_delete (g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][p_ipuc_param->vrf_id],
                               key, p_ipuc_param->masklen, (trie_node_t **) &p_route_db_payload, 1);
        mem_free(p_route_db_payload);
    }
#endif

    /* 3.2 clear sram */
    if (!is_inner)
    {
        sys_ipuc_info_t route_info_void;

        sal_memset(&route_info_void, 0, sizeof(sys_ipuc_info_t));

        CTC_ERROR_RETURN(_sys_nalpm2_write_sram_l1(lchip, p_lkp_rlt->p_l0_item, &route_info_void,
                                                  p_lkp_rlt->snake_idx[LEVEL1], p_lkp_rlt->entry_offset[LEVEL1], 0, NULL, NULL));
    }

    /* 4. update stats */
    g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]--;
    p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]] = NULL;

    /* 5. delete route cover */
    CTC_ERROR_RETURN(_sys_nalpm2_deletes_route_cover(lchip, p_lkp_rlt->p_l0_item, p_trie_l1_info->p_l1_info, p_lkp_rlt->total_skip_len));

    /* 6. free memory */
    //mem_free(p_trie_l1_info->p_l1_info);  /* be freed in ipuc func */
    mem_free(p_trie_l1_info);
    CTC_BIT_UNSET(NALPM2_BUCKET_ARRAY_L1(lchip, p_lkp_rlt->p_l0_item->sram_idx).bitmap[p_lkp_rlt->snake_idx[LEVEL1]], p_lkp_rlt->entry_offset[LEVEL1]);

    /* 7. update bucket */
    CTC_ERROR_RETURN(_sys_nalpm2_bucket_list_update_l1(lchip, p_lkp_rlt->p_l0_item->sram_idx, -1));

    /* 8. release level1 DB & tcam */
    if (!p_lkp_rlt->p_l0_item->trie->trie)
    {
        void *p_node1 = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]->trie, sys_nalpm2_trie_l0_item_t, node);
        void *p_node2 = CONTAINER_OF(p_lkp_rlt->p_l0_item, sys_nalpm2_trie_l0_item_t, l0_item);

        /* 8.1 this node is not the root node */
        if (p_node1 != p_node2)
        {
            sys_nalpm2_info_t *p_l1_root_info = NULL;

            /* 8.1.0 prepare data */
            sal_memset(key, 0, sizeof(key));
            p_l1_root_info = p_lkp_rlt->p_l0_item->p_l1_root_info;

            /* 8.1.0.1 level1 sram root needs convert!!! */
            if (p_l1_root_info->tcam_masklen)
            {
                sal_memcpy(key, p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
                SYS_IPV6_IP_SORT(ip_ver, key);
                SYS_NALPM_CONVERT_TO_LSB(key, p_l1_root_info->tcam_masklen, ip_ver);
            }

            /* 8.1.1 release level0 sram */
            CTC_ERROR_RETURN(_sys_nalpm2_ln_del_l0(lchip, p_ipuc_param, p_lkp_rlt->p_tcam_item, p_lkp_rlt->p_l0_item, is_inner));

            /* 8.1.2 destroy trie */
            CTC_ERROR_RETURN(sys_nalpm_trie_destroy(p_lkp_rlt->p_l0_item->trie));

            /* 8.1.3 delete l0 item from trie */
            CTC_ERROR_RETURN(sys_nalpm_trie_delete(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id],
                                                    key, p_lkp_rlt->p_l0_item->p_l1_root_info->tcam_masklen, (trie_node_t**)&p_trie_l0_item, 0));

            /* 8.1.4 free level1 sram index */
            CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free_l1(lchip, p_lkp_rlt->p_l0_item->sram_idx, ip_ver));

            /* 8.1.5 free memory */
            mem_free(p_trie_l0_item->l0_item.p_l1_root_info);
            p_trie_l0_item->l0_item.p_l1_root_info = NULL;
            mem_free(p_trie_l0_item);
        }
    }

    /* 9. if count equal 0, deinit vrf */
    if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0 || g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]->trie == NULL)
    {
        CTC_ERROR_RETURN(_sys_nalpm2_route_vrf_deinit(lchip, p_sys_ipuc_param));
    }

    /* 10. update stats */
    g_sys_nalpm2_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]--;
    g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL1][ip_ver]--;

    return ret;
}

int32
sys_nalpm2_update(uint8 lchip, void* p_sys_ipuc_param_v, uint32 ad_index)
{
    sys_ipuc_param_t* p_sys_ipuc_param = (sys_ipuc_param_t*)p_sys_ipuc_param_v;
    ctc_ipuc_param_t* p_ipuc_param = &p_sys_ipuc_param->param;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t* p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_info_t* p_nalpm_info = NULL;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = p_ipuc_param->ip_ver;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* -1. update default route */
    if(p_ipuc_param->masklen == 0)
    {
        sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;

        if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][p_ipuc_param->vrf_id])
        {
            return CTC_E_NOT_EXIST;
        }

        p_trie_tcam_item = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][p_ipuc_param->vrf_id]->trie, sys_nalpm2_trie_tcam_item_t, node);

        /* -1.1 write tcam */
        CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, &(p_trie_tcam_item->tcam_item), DO_UPDATE, ad_index));

        /* -1.2 update tcam router cover */
        CTC_ERROR_RETURN(_sys_nalpm2_default_route_cover(lchip, ip_ver, p_ipuc_param->vrf_id, ad_index));

        /* -1.3 update l0 sram router cover */
        CTC_ERROR_RETURN(_sys_nalpm2_default_lvl0_route_cover(lchip, ip_ver, p_ipuc_param->vrf_id, ad_index));

        /* -1.4 set tcam idx to ipuc info */
        p_sys_ipuc_param->info->tcam_idx = p_trie_tcam_item->tcam_item.tcam_idx;

        /* -1.5 store /0 ipuc info to tcam item for wb*/
        /* for /0 tcam item ,its p_l0_root_AD will not use as route cover,reuse it for store /0 route info*/
        p_trie_tcam_item->tcam_item.p_l0_root_AD = (ad_index == INVALID_DRV_NEXTHOP_OFFSET) ? NULL : p_sys_ipuc_param->info;

        return ret;
    }

    /* 0. prepare data */
    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_nalpm_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));

    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_nalpm_info->ip_ver = ip_ver;
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    p_nalpm_info->ad_idx = ad_index;

    /* 1. lookup sw node */
    CTC_ERROR_GOTO(_sys_nalpm2_route_lkp_l1(lchip, p_nalpm_info, p_lkp_rlt), ret, error_proc);
    if(!p_lkp_rlt->sram_hit[LEVEL1])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "(%d) can't find ip[%x]\n",__LINE__, p_nalpm_info->ip[0]);
        ret = CTC_E_NOT_EXIST;
        goto error_proc;
    }

    /* 2. update ad index */
    p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]]->ad_index = p_nalpm_info->ad_idx;

    /* 3. write L1 SRAM */
    CTC_ERROR_GOTO(_sys_nalpm2_write_sram_l1(lchip, p_lkp_rlt->p_l0_item,
                                         p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]],
                                         p_lkp_rlt->snake_idx[LEVEL1], p_lkp_rlt->entry_offset[LEVEL1], 1, NULL, NULL),ret, error_proc);

    /* 4. update router cover */
    CTC_ERROR_GOTO(_sys_nalpm2_add_route_cover(lchip, p_lkp_rlt->p_l0_item,
                                                      p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]],
                                                      0, p_lkp_rlt->total_skip_len, 0, NULL), ret, error_proc);

error_proc:
    if(p_nalpm_info)
        mem_free(p_nalpm_info);

    return ret;
}

int32
sys_nalpm2_ageing_opt(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, uint8 opt, uint8 *p_hit)
{
    sys_nalpm2_info_t* p_nalpm_info = NULL;
    sys_ipuc_info_t* p_l1_info = NULL;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    ctc_ipuc_param_t* p_ipuc_param= &p_sys_ipuc_param->param;
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(p_ipuc_param->masklen== 0)
    {
        return ret;
    }

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;

    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_nalpm_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));

    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    p_nalpm_info->ip_ver = ip_ver;

    /* 1. lookup sw node */
    sal_memset(p_lkp_rlt, 0, sizeof(sys_nalpm2_route_store_info_t));
    CTC_ERROR_GOTO(_sys_nalpm2_route_lkp_l1(lchip, p_nalpm_info, p_lkp_rlt), ret, end);

    if (!p_lkp_rlt->sram_hit[LEVEL1])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sys_nalpm2_ageing_opt\r\n", __LINE__);
        ret =  CTC_E_NOT_EXIST;
        goto end;
    }

    p_l1_info = p_lkp_rlt->p_l0_item->p_l1_info_array[p_lkp_rlt->snake_idx[LEVEL1]][p_lkp_rlt->entry_offset[LEVEL1]];

    /* 2. set/get aging bit */
    ret = _sys_nalpm2_add_route_cover(lchip, p_lkp_rlt->p_l0_item, p_l1_info, 0, p_lkp_rlt->total_skip_len, opt, p_hit);

end:
    if(p_nalpm_info)
        mem_free(p_nalpm_info);

    return ret;
}

int32
sys_nalpm2_auto_merge(uint8 lchip, uint8 enable)
{
    SYS_NALPM2_INIT_CHECK;
    g_sys_nalpm2_master[lchip]->frag_arrange_enable = enable;
    return CTC_E_NONE;
}

int32
sys_nalpm2_set_fragment_status(uint8 lchip, uint8 ip_ver, uint8 status)
{
    SYS_NALPM2_INIT_CHECK;
    g_sys_nalpm2_master[lchip]->frag_arrange_status[ip_ver] = status;
    return CTC_E_NONE;
}

int32
sys_nalpm2_get_fragment_status(uint8 lchip, uint8 ip_ver, uint8* status)
{
    SYS_NALPM2_INIT_CHECK;
    *status = g_sys_nalpm2_master[lchip]->frag_arrange_status[ip_ver];
    return CTC_E_NONE;
}

int32
sys_nalpm2_get_fragment_auto_enable(uint8 lchip, uint8* enable)
{
    SYS_NALPM2_INIT_CHECK;
    *enable = g_sys_nalpm2_master[lchip]->frag_arrange_enable;
    return CTC_E_NONE;
}

int32
sys_nalpm2_move_hit_en(uint8 lchip, uint8 enable)
{
    LCHIP_CHECK(lchip);
    SYS_NALPM2_INIT_CHECK;
    SYS_IPUC_LOCK;
    g_sys_nalpm2_master[lchip]->move_hit_en = enable ? 1 : 0;
    SYS_IPUC_UNLOCK;
    return CTC_E_NONE;
}

#define _________DUMP_________
STATIC int32
_sys_nalpm2_dump_route_trie_node_l1(trie_node_t* node, void* data);

int32
_sys_nalpm2_dump_route_trie_node_l0(trie_node_t* node, void* data)
{
    trie_dump_node_t* p_dump_node = (trie_dump_node_t *)data;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    trie_node_t* p_father = p_dump_node->father;
    trie_node_t* p_root = p_dump_node->root;
    sys_nalpm2_info_t* p_l0_info = NULL;
    trie_node_t* trie = node;
    char* node_type_str[3] = {"T", "L", "R"};
    char buf[CTC_IPV6_ADDR_STR_LEN];
    char bit_str[32] = { 0 };
    uint32 level = p_dump_node->father_lvl;
    uint32 node_type = 0;
    trie_dump_node_t dump_node;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_dump_node->lchip;
#endif

    if (NULL == trie)
    {
        return CTC_E_NONE;
    }

    /* 0. prepare data */
    sal_memset(bit_str, 0, sizeof(bit_str));
    NALPM2_PFX2BITS(trie->skip_addr, trie->skip_len, bit_str);

    /* 0.1 root node */
    if (p_root == trie)
    {
        node_type = 0;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    else if (p_father->child[0].child_node == trie)
    {
        node_type = 1;
    }
    else
    {
        node_type = 2;
    }

    /* 1. dump node */
    while (level-- != 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    ");
    }

    /* 1.1 dump payload node */
    if (trie->type == PAYLOAD)
    {
        p_trie_l0_info = (sys_nalpm2_trie_l0_info_t* )node;
        p_l0_info = p_trie_l0_info->p_l0_info;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p],",
         node_type_str[node_type], p_dump_node->father_lvl, trie,"P",
         trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
         trie->child[1].child_node);
         NALPM2_GEN_IP_STR(buf, p_l0_info->ip_ver, p_l0_info->ip, p_l0_info->route_masklen);
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", buf);
         SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "AD-idx:[0x%x]\n", p_l0_info->ad_idx);

        if(p_l0_info->p_l0_item->trie->trie)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------route num:[%u]----------\n", p_l0_info->p_l0_item->trie->trie->count);
            dump_node.father = p_l0_info->p_l0_item->trie->trie;
            dump_node.root = p_l0_info->p_l0_item->trie->trie;
            dump_node.father_lvl = p_dump_node->father_lvl;
            dump_node.user_data = p_l0_info;
            return sys_nalpm_trie_traverse(p_l0_info->p_l0_item->trie->trie, _sys_nalpm2_dump_route_trie_node_l1, &dump_node, _TRIE_DUMP_TRAVERSE);
        }
    }
    /* 1.2 dump internal node */
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p]\n",
        node_type_str[node_type], p_dump_node->father_lvl, trie,"I",
        trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
        trie->child[1].child_node);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_dump_route_trie_node_l1(trie_node_t* node, void* data)
{
    trie_dump_node_t* p_dump_node = (trie_dump_node_t *)data;
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info = NULL;
    trie_node_t* p_father = p_dump_node->father;
    trie_node_t* p_root = p_dump_node->root;
    sys_nalpm2_info_t* p_l0_info = NULL;
    sys_ipuc_info_t* p_l1_info = NULL;
    trie_node_t* trie = node;
    char* node_type_str[3] = {"T", "L", "R"};
    char buf[CTC_IPV6_ADDR_STR_LEN];
    char bit_str[32] = { 0 };
    uint32 level = p_dump_node->father_lvl;
    uint32 node_type = 0;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_dump_node->lchip;
#endif
    if (NULL == trie)
    {
        return CTC_E_NONE;
    }

    /* 0. prepare data */
    p_l0_info = p_dump_node->user_data;
    sal_memset(bit_str, 0, sizeof(bit_str));
    NALPM2_PFX2BITS(trie->skip_addr, trie->skip_len, bit_str);

    /* 0.1 root node */
    if (p_root == trie)
    {
        node_type = 0;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    else if (p_father->child[0].child_node == trie)
    {
        node_type = 1;
    }
    else
    {
        node_type = 2;
    }

    /* 1. dump node */
    while (level-- != 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    ");
    }

    /* 1.1 dump payload node */
    if (trie->type == PAYLOAD)
    {
        p_trie_l1_info = (sys_nalpm2_trie_l1_info_t* )node;
        p_l1_info = p_trie_l1_info->p_l1_info;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p],",
        node_type_str[node_type], p_dump_node->father_lvl, trie,"P",
        trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
        trie->child[1].child_node);
        NALPM2_GEN_IP_STR(buf, p_l0_info->ip_ver, p_l1_info->ip.ipv6, p_l1_info->masklen);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%s\n", buf);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "AD-idx:[0x%x]\n", p_l1_info->ad_index);
    }
    /* 1.2 dump internal node */
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p]\n",
        node_type_str[node_type], p_dump_node->father_lvl, trie,"I",
        trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
        trie->child[1].child_node);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_dump_pfx_trie_node(trie_node_t* node, void* data)
{
    trie_dump_node_t *p_dump_node = (trie_dump_node_t *)data;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    sys_nalpm2_info_t *p_l0_root_info = NULL;
    trie_node_t *p_father = p_dump_node->father;
    trie_node_t *p_root = p_dump_node->root;
    trie_node_t * trie = node;
    char* node_type_str[3] = {"T", "L", "R"};
    char bit_str[32] = { 0 };
    uint32 level = p_dump_node->father_lvl;
    uint32 node_type = 0;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = p_dump_node->lchip;
#endif
    if (NULL == trie)
    {
        return CTC_E_NONE;
    }

    /* 0. prepare data */
    sal_memset(bit_str, 0, sizeof(bit_str));
    NALPM2_PFX2BITS(trie->skip_addr, trie->skip_len, bit_str);
    p_trie_tcam_item = (sys_nalpm2_trie_tcam_item_t* )node;
    p_l0_root_info = p_trie_tcam_item->tcam_item.p_l0_root_info;

    /* 0.1 root node */
    if (p_root == trie)
    {
        node_type = 0;
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");
    }
    /* 0.2 child node */
    else if (p_father->child[0].child_node == trie)
    {
        node_type = 1;
    }
    else
    {
        node_type = 2;
    }

    /* 1. dump node */
    while (level-- != 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "    ");
    }

    /* 1.1 dump payload node */
    if (trie->type == PAYLOAD)
    {
        if(p_l0_root_info == NULL)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "p_l0_root_info == NULL\n");
            return CTC_E_NONE;
        }
        if (CTC_IP_VER_4 == p_l0_root_info->ip_ver)
        {

            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
                             "tcam_idx[%u], %s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p], pfx_IPv4[0x%x/%d]\n",
                             p_trie_tcam_item->tcam_item.tcam_idx , node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
                             trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
                             trie->child[1].child_node,
                             p_l0_root_info->ip[0], p_l0_root_info->tcam_masklen);
        }
        else
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
                             "tcam_idx[%u], %s%d[%p], type[%s], skip_addr/len[0x%x/%d], cnt[%d] Child[%p/%p], pfx_IPv6[0x%x:0x%x:0x%x:0x%x/%d], trie[%p], &trie->skip_len[%d], &child[%p]\n",
                             p_trie_tcam_item->tcam_item.tcam_idx , node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
                             trie->skip_addr, trie->skip_len, trie->count, trie->child[0].child_node,
                             trie->child[1].child_node,
                             p_l0_root_info->ip[3],
                             p_l0_root_info->ip[2],
                             p_l0_root_info->ip[1],
                             p_l0_root_info->ip[0],
                             p_l0_root_info->tcam_masklen,
                             trie, trie->skip_len, trie->child);
        }
    }
    /* 1.2 dump internal node */
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,
        "%s%d[%p], type[%s], skip_addr/len[%db'%s/%d], cnt[%d] Child[%p/%p]\n",
         node_type_str[node_type], p_dump_node->father_lvl, trie, (trie->type == PAYLOAD) ? "P" : "I",
         trie->skip_len, bit_str, trie->skip_len, trie->count, trie->child[0].child_node,
         trie->child[1].child_node);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_dump_route_l0(uint8 lchip, sys_nalpm2_info_t* p_l0_info)
{
    char buf[CTC_IPV6_ADDR_STR_LEN];

    NALPM2_GEN_IP_STR(buf, p_l0_info->ip_ver, p_l0_info->ip, p_l0_info->route_masklen);

    if (p_l0_info->ip_ver == CTC_IP_VER_4)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-28s\n", p_l0_info->hw_position[0], p_l0_info->hw_position[1], buf);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-44s\n", p_l0_info->hw_position[0], p_l0_info->hw_position[1], buf);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_dump_route_l1(uint8 lchip, sys_ipuc_info_t* p_l1_info)
{
    char buf[CTC_IPV6_ADDR_STR_LEN];
    uint32 key[4] = {0};

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%20s", "");

    sal_memcpy(key, &(p_l1_info->ip.ipv4), IP_ADDR_SIZE(SYS_IPUC_VER(p_l1_info)));

    NALPM2_GEN_IP_STR(buf, SYS_IPUC_VER(p_l1_info), key, p_l1_info->masklen);

    if (CTC_IP_VER_4 == SYS_IPUC_VER(p_l1_info))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-28s\n", p_l1_info->snake_idx, p_l1_info->entry_offset, buf);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-44s\n", p_l1_info->snake_idx, p_l1_info->entry_offset, buf);
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_dump_route_trie_l1(uint8 lchip, sys_nalpm2_l0_item_t* p_l0_item)
{
    sys_nalpm2_info_t* p_l1_root_info = NULL;
    char buf[CTC_IPV6_ADDR_STR_LEN];
    uint32 ip[4] = {0};
    uint8 cnt = 0;
    uint8 i = 0;
    uint8 j = 0;

    if (p_l0_item == NULL)
    {
        return 0;
    }

    /* 0. prepare data */
    p_l1_root_info = p_l0_item->p_l1_root_info;

    /* 1. dump level1 info */
    /* 1.1 dump level1 position */
    sal_memcpy(ip, p_l1_root_info->ip, IP_ADDR_SIZE(p_l1_root_info->ip_ver));
    NALPM2_GEN_IP_STR(buf, p_l1_root_info->ip_ver, ip, p_l1_root_info->tcam_masklen);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%20s", "");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "SramIdx:%d, Sub:%d, Prefix:%s\n", p_l0_item->sram_idx, p_l0_item->sub_bkt, buf);

    /* 1.2 dump level0 position */
    if (p_l0_item->p_tcam_item)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%20sLevel0 Tcam Index:%4d, SramIdx:%d\n","", p_l0_item->p_tcam_item->tcam_idx, p_l0_item->p_tcam_item->sram_idx);
    }

    /* 1.2 dump level0 default route */
    if (p_l0_item->p_l1_root_AD)
    {
        uint32 key[4] = {0};

        sal_memcpy(key, &(p_l0_item->p_l1_root_AD->ip.ipv4), IP_ADDR_SIZE(SYS_IPUC_VER(p_l0_item->p_l1_root_AD)));

        NALPM2_GEN_IP_STR(buf, p_l1_root_info->ip_ver, key, p_l0_item->p_l1_root_AD->masklen)
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%20s*AD Route: %s\n", "", buf);
    }

    /* 1.3 dump level1 detail info */
    for (i = 0; i < SYS_NALPM2_MAX_SNACKE_L1; i++)
    {
        for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4_L1; j++)
        {
            if (NULL == p_l0_item->p_l1_info_array[i][j])
            {
                continue;
            }

            _sys_nalpm2_dump_route_l1(lchip, p_l0_item->p_l1_info_array[i][j]);

            cnt++;
        }
    }

    /* 1.4 dump stats */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%20s", "");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Total Entry: %d\n", cnt);

    return 0;
}


int32
_sys_nalpm2_dump_route_trie(trie_node_t* node, void* data)
{
    trie_dump_node_t *p_dump_node = (trie_dump_node_t*)data;
    sys_nalpm2_dump_route_info_t* p_dump = (sys_nalpm2_dump_route_info_t*)p_dump_node->user_data;
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = (sys_nalpm2_trie_tcam_item_t*)node;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_info_t* p_l0_root_info = NULL;
    sys_ipuc_info_t* p_l0_root_AD = NULL;
    trie_dump_node_t dump_node;
    int32 ret = CTC_E_NONE;
    uint8 lchip = p_dump_node->lchip;

    if (INTERNAL == p_trie_tcam_item->node.type || NULL == p_dump)
    {
        return 0;
    }

    p_tcam_item = &p_trie_tcam_item->tcam_item;
    if(p_tcam_item->trie == NULL)
    {
        return 0;
    }
    p_l0_root_info = p_tcam_item->p_l0_root_info;

    /* 1. dump mode 2 info */
    if (p_dump->mode == 0 && p_dump->index != p_tcam_item->tcam_idx)
    {
        return 0;
    }
    else if(p_dump->mode == 1 && p_dump->index != p_tcam_item->sram_idx)
    {
        return 0;
    }
    else if (p_dump->mode == 2)
    {
        sys_ipuc_info_t ipuc_info;
        uint8 found = 0;
        uint8 i = 0;
        uint8 j = 0;

        /* 1.0 prepare data */
        sal_memset(&ipuc_info, 0, sizeof(ipuc_info));

        sal_memcpy(&(ipuc_info.ip), p_dump->p_nalpm_info->ip, IP_ADDR_SIZE(p_dump->p_nalpm_info->ip_ver));
        ipuc_info.masklen = p_dump->p_nalpm_info->route_masklen;
        ipuc_info.vrf_id = p_dump->p_nalpm_info->vrf_id;
        if (CTC_IP_VER_6 == p_dump->p_nalpm_info->ip_ver)
        {
            CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_IS_IPV6);
        }

        /* 1.1 lookup route */
        for (i = 0; i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip); i++)
        {
            for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4_L0; j++)
            {
                if (NULL == p_tcam_item->p_l0_info_array[i][j])
                {
                    continue;
                }

                if (p_tcam_item->p_l0_info_array[i][j]->p_l0_item)
                {
                    sys_nalpm2_l0_item_t* p_l0_item = p_tcam_item->p_l0_info_array[i][j]->p_l0_item;
                    uint8 m = 0;
                    uint8 n = 0;

                    for (m = 0; m < NALPM2_BUKCET_SNAKE_NUM_L1(lchip); m++)
                    {
                        for (n = 0; n < ROUTE_NUM_PER_SNAKE_V4_L1; n++)
                        {
                            if (NULL == p_l0_item->p_l1_info_array[m][n])
                            {
                                continue;
                            }

                            if (0 == _sys_nalpm2_route_cmp_l1(lchip, &ipuc_info, p_l0_item->p_l1_info_array[m][n]))
                            {
                                found = 1;
                                break;
                            }
                        }

                        if (found == 1)
                        {
                            break;
                        }

                    }
                }

                if (found == 1)
                {
                    break;
                }
            }

            if (found == 1)
            {
                break;
            }
        }

        if (found == 0)
        {
            return 0;
        }
    }

    /* 2. dump info */
    if(p_dump->detail == 0)
    {
        char buf[CTC_IPV6_ADDR_STR_LEN];
        uint8 cnt = 0;
        uint8 i = 0;
        uint8 j = 0;

        NALPM2_GEN_IP_STR(buf, p_l0_root_info->ip_ver, p_l0_root_info->ip, p_l0_root_info->tcam_masklen)

        /* 2.1 dump tcam info */
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n\nTcam Index: %4d\n", p_tcam_item->tcam_idx);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Sram Index: %4d Sub:%d\n", p_tcam_item->sram_idx, p_tcam_item->sub_bkt);
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Prefix: %s %d\n", buf, p_tcam_item->p_l0_root_info->vrf_id);

        /* 2.2 dump tcam defaule AD */
        if (p_tcam_item->p_l0_root_AD)
        {
            NALPM2_GEN_IP_STR(buf, p_l0_root_info->ip_ver, p_tcam_item->p_l0_root_AD->ip.ipv6, p_tcam_item->p_l0_root_AD->masklen)
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "*AD Route: %s\n", buf);
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "==================================\n");

        /* 2.3 dump sram */
        for (i = 0; i < NALPM2_BUKCET_SNAKE_NUM_L0(lchip); i++)
        {
            for (j = 0; j < ROUTE_NUM_PER_SNAKE_V4_L0; j++)
            {
                if (NULL == p_tcam_item->p_l0_info_array[i][j])
                {
                    continue;
                }

                /* 2.3.1 dump level0 sram */
                _sys_nalpm2_dump_route_l0(lchip, p_tcam_item->p_l0_info_array[i][j]);

                cnt++;

                /* 2.3.2 dump level1 sram */
                if (p_tcam_item->p_l0_info_array[i][j]->p_l0_item)
                {
                    sys_nalpm2_l0_item_t *p_l0_item = p_tcam_item->p_l0_info_array[i][j]->p_l0_item;
                    _sys_nalpm2_dump_route_trie_l1(lchip, p_l0_item);
                }
            }
        }

        /* 2.4 dump stats */
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Sram Used Entry: %d\n", NALPM2_BUCKET_USE_CNT_L0(lchip, p_tcam_item->sram_idx));
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Total Entry: %d\n", cnt);
    }
    else
    {
        /* 2.1 prepare data */
        dump_node.father = p_tcam_item->trie->trie;
        dump_node.root = p_tcam_item->trie->trie;
        dump_node.father_lvl = 0;
        p_l0_root_AD = p_tcam_item->p_l0_root_AD;

        if (NULL == p_tcam_item->trie->trie)
        {
            return ret;
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------AD route----------\n");

        /* 2.2 dump covered route */
        if(p_l0_root_AD != NULL)
        {
            if (CTC_FLAG_ISSET(p_l0_root_AD->route_flag, SYS_IPUC_FLAG_IS_IPV6))
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " pfx_IPv6[0x%x:0x%x:0x%x:0x%x/%d]\n",
                                 p_l0_root_AD->ip.ipv6[3],
                                 p_l0_root_AD->ip.ipv6[2],
                                 p_l0_root_AD->ip.ipv6[1],
                                 p_l0_root_AD->ip.ipv6[0],
                                 p_l0_root_AD->masklen);

            }
            else
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " pfx_IPv4[0x%x/%d]\n", p_l0_root_AD->ip.ipv4, p_l0_root_AD->masklen);
            }
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "AD-idx:[0x%x]\n", p_l0_root_AD->ad_index);
        }

        /* 2.3 dump trie route */
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-----------L0 prefix num:[%u]----------\n", p_tcam_item->trie->trie->count);
        ret = sys_nalpm_trie_traverse(p_tcam_item->trie->trie, _sys_nalpm2_dump_route_trie_node_l0, &dump_node, _TRIE_DUMP_TRAVERSE);
    }

    if (p_dump->mode != 3)
    {
       return -1;
    }

    return ret;
}

int32
sys_nalpm2_show_route_info(uint8 lchip, void* p_ipuc_param_v)
{
    ctc_ipuc_param_t* p_ipuc_param = (ctc_ipuc_param_t *)p_ipuc_param_v;
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_info_t*  p_nalpm_info = NULL;
    sys_ipuc_tcam_data_t tcam_data;
    uint32 table_id[2] = {0};
    uint8 entry_offset[2] = {0};
    uint8 snake_idx[2] = {0};
    int32 ret = CTC_E_NONE;
    uint32 hw_sram_idx = 0;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    SYS_NALPM2_INIT_CHECK;

    /* 0. prepare data */
    ip_ver = p_ipuc_param->ip_ver;

    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_nalpm_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));
    sal_memset(p_lkp_rlt, 0, sizeof(sys_nalpm2_route_store_info_t));

    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    p_nalpm_info->ip_ver = ip_ver;

    /* 1. lookup sw node */
    ret = _sys_nalpm2_route_lkp_l1(lchip, p_nalpm_info, p_lkp_rlt);
    if(ret < 0 || (!p_lkp_rlt->sram_hit[LEVEL1] && p_ipuc_param->masklen != 0))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "can't find route\n");
        mem_free(p_nalpm_info);
        return CTC_E_NOT_EXIST;
    }

    /* 1.0 prepare data */
    p_tcam_item = p_lkp_rlt->p_tcam_item;
    p_l0_item = p_lkp_rlt->p_l0_item;

    if (p_l0_item && p_l0_item->p_l1_root_info)
    {
        snake_idx[LEVEL0] = p_l0_item->p_l1_root_info->hw_position[0];
        entry_offset[LEVEL0] = p_l0_item->p_l1_root_info->hw_position[1];
    }
    snake_idx[LEVEL1] = p_lkp_rlt->snake_idx[LEVEL1];
    entry_offset[LEVEL1] = p_lkp_rlt->entry_offset[LEVEL1];

    mem_free(p_nalpm_info);

    /* 2. sys_tsingma_ipuc_tcam_show_key */
    if (MCHIP_IPUC(lchip)->show_tcam_key)
    {
        tcam_data.key_type = SYS_IPUC_TCAM_FLAG_ALPM;
        tcam_data.key_index = p_tcam_item->tcam_idx;
        tcam_data.masklen = p_ipuc_param->masklen;
        tcam_data.ipuc_param = p_ipuc_param;
        MCHIP_IPUC(lchip)->show_tcam_key(lchip, &tcam_data);
    }

    if(p_ipuc_param->masklen == 0)
    {
        return ret;
    }

    /* 3. show ip address */
    if (p_tcam_item->p_l0_root_info)
    {
        if (CTC_IP_VER_4 == ip_ver)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:[0x%08x/%d]\n", "tcam prefix", p_tcam_item->p_l0_root_info->ip[0], p_tcam_item->p_l0_root_info->tcam_masklen);
        }
        else
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:[0x%08x:%08x:%08x:%08x/%d]\n",
                             "tcam prefix",
                             p_tcam_item->p_l0_root_info->ip[3],
                             p_tcam_item->p_l0_root_info->ip[2],
                             p_tcam_item->p_l0_root_info->ip[1],
                             p_tcam_item->p_l0_root_info->ip[0],
                             p_tcam_item->p_l0_root_info->tcam_masklen);
        }
    }

    /* 4. show sram info */
    /* 4.1 level0 */
    hw_sram_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item->sram_idx, snake_idx[LEVEL0]);

    _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item->sram_type, snake_idx[LEVEL0], &table_id[0], &table_id[1]);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n\n[alpm level%d]\n", LEVEL0);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", DRV_TABLE_NAME(lchip, table_id[0]), hw_sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "Sram index", p_tcam_item->sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "snake index", snake_idx[LEVEL0]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "entry_offset", entry_offset[LEVEL0]);

    /* 4.1 level1 */
    hw_sram_idx = NALPM2_HW_SRAM_INDEX_L1(lchip, p_l0_item->sram_idx, snake_idx[LEVEL1]);

    _sys_nalpm2_get_table_id_l1(lchip, p_l0_item->sram_type, snake_idx[LEVEL1], &table_id[0], &table_id[1]);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n\n[alpm level%d]\n", LEVEL1);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", DRV_TABLE_NAME(lchip, table_id[0]), hw_sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "Sram index", p_l0_item->sram_idx);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "snake index", snake_idx[LEVEL1]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, " --%-30s:%d\n", "entry_offset", entry_offset[LEVEL1]);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\n");

    return ret;
}

int32
sys_nalpm2_show_sram_usage(uint8 lchip)
{
    sys_usw_opf_t opf;
    uint32 entry_num = 0;

    SYS_NALPM2_INIT_CHECK;

    opf.pool_index = 0;
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;

    sys_usw_ftm_query_table_entry_num(lchip, DsNeoLpmIpv4Bit32Snake_t, &entry_num);

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Lchip %d SRAM usage: %u/%u 3W\n", lchip, sys_usw_opf_get_alloced_cnt(lchip, &opf), entry_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "-------------------------------------------------------\n");
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Auto run fragment merge: %u\n", g_sys_nalpm2_master[lchip]->frag_arrange_enable);

    return CTC_E_NONE;
}

int32
sys_nalpm2_show_status(uint8 lchip)
{
    uint32 v6_128_tcam_entry = 0;
    uint32 v6_64_tcam_entry = 0;
    uint32 v4_tcam_entry = 0;
    uint32 v6_128_entry = 0;
    uint32 v4_usage_cnt = 0;
    uint32 v6_usage_cnt = 0;
    uint32 v6_64_entry = 0;
    uint32 v4_entry = 0;
    uint16 v6_128_bkt_ent = 0;
    uint16 v6_64_bkt_ent = 0;
    uint16 v4_bkt_ent = 0;

    SYS_NALPM2_INIT_CHECK;

    /* 0. prepare data */
    v4_tcam_entry = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_4][SYS_TBL_TCAM]
        + p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT]
        + p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM];

    if (p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT])
    {
        v6_64_tcam_entry = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM_SHORT] / 2
        + p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] / 4;
        v6_128_tcam_entry = p_usw_ipuc_master[lchip]->max_entry_num[CTC_IP_VER_6][SYS_TBL_TCAM] / 4;
    }
    else
    {
        v6_64_tcam_entry =  v4_tcam_entry / 2;
        v6_128_tcam_entry =  v4_tcam_entry / 4;
    }

    /* 1. show mode */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-28s: %15d\n", "ipv6_couple  Mode", g_sys_nalpm2_master[lchip]->ipv6_couple_mode);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-28s: %15d\n", "Split Mode", g_sys_nalpm2_master[lchip]->split_mode);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "%-28s: %15d\n", "Ipsa Enable", g_sys_nalpm2_master[lchip]->ipsa_enable);

    /* 2. level0 */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nLevel %d\n", LEVEL0);

    v4_bkt_ent = NALPM2_BUCKET_FMT_MAX_L0(lchip, NALPM2_FMT_V4);
    v6_64_bkt_ent = NALPM2_BUCKET_FMT_MAX_L0(lchip, NALPM2_FMT_V6_64);
    v6_128_bkt_ent = NALPM2_BUCKET_FMT_MAX_L0(lchip, NALPM2_FMT_V6_128);

    v4_entry = v4_bkt_ent * MIN(NALPM2_BUCKET_L0(lchip).real_bkt_depth, v4_tcam_entry);
    v6_64_entry = v6_64_bkt_ent * MIN(NALPM2_BUCKET_L0(lchip).real_bkt_depth, v6_64_tcam_entry);
    v6_128_entry = v6_128_bkt_ent * MIN(NALPM2_BUCKET_L0(lchip).real_bkt_depth, v6_128_tcam_entry);

    v4_usage_cnt = g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][CTC_IP_VER_4];
    v6_usage_cnt = g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][CTC_IP_VER_6];

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Bucket Depth", NALPM2_BUCKET_L0(lchip).bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Real Bucket Depth", NALPM2_BUCKET_L0(lchip).real_bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Snake Per Group", NALPM2_BUCKET_L0(lchip).snake_per_group);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Snake Group num", NALPM2_BUCKET_L0(lchip).snake_group_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv4 Entry/Bucket", v4_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv6(64) Entry/Bucket", v6_64_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv6(128) Entry/Bucket", v6_128_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv4 Bucket Usage", NALPM2_BUCKET_L0(lchip).bkt_usage[NALPM2_FMT_V4]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv6(64) Bucket Usage", NALPM2_BUCKET_L0(lchip).bkt_usage[NALPM2_FMT_V6_64]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv6(128) Bucket Usage", NALPM2_BUCKET_L0(lchip).bkt_usage[NALPM2_FMT_V6_128]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv4 Alpm Entry", v4_usage_cnt);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL0, "Ipv6 Alpm Entry",  v6_usage_cnt);

    /* 3. level1 */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "\nLevel %d\n", LEVEL1);

    v4_bkt_ent = NALPM2_BUCKET_FMT_MAX_L1(lchip, NALPM2_FMT_V4);
    v6_64_bkt_ent = NALPM2_BUCKET_FMT_MAX_L1(lchip, NALPM2_FMT_V6_64);
    v6_128_bkt_ent = NALPM2_BUCKET_FMT_MAX_L1(lchip, NALPM2_FMT_V6_128);

    v4_entry = v4_bkt_ent * MIN(NALPM2_BUCKET_L1(lchip).real_bkt_depth, v4_entry);
    v6_64_entry = v6_64_bkt_ent * MIN(NALPM2_BUCKET_L1(lchip).real_bkt_depth, v6_64_entry);
    v6_128_entry = v6_128_bkt_ent * MIN(NALPM2_BUCKET_L1(lchip).real_bkt_depth, v6_128_entry);

    v4_usage_cnt = g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL1][CTC_IP_VER_4];
    v6_usage_cnt = g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL1][CTC_IP_VER_6];

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Bucket Depth", NALPM2_BUCKET_L1(lchip).bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Real Bucket Depth", NALPM2_BUCKET_L1(lchip).real_bkt_depth);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Snake Per Group", NALPM2_BUCKET_L1(lchip).snake_per_group);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Snake Group num", NALPM2_BUCKET_L1(lchip).snake_group_num);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv4 Entry/Bucket", v4_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv6(64) Entry/Bucket", v6_64_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv6(128) Entry/Bucket", v6_128_bkt_ent);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv4 Bucket Usage", NALPM2_BUCKET_L1(lchip).bkt_usage[NALPM2_FMT_V4]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv6(64) Bucket Usage", NALPM2_BUCKET_L1(lchip).bkt_usage[NALPM2_FMT_V6_64]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv6(128) Bucket Usage", NALPM2_BUCKET_L1(lchip).bkt_usage[NALPM2_FMT_V6_128]);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv4 Alpm Entry", v4_usage_cnt);
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "L%d %-25s: %15d\n", LEVEL1, "Ipv6 Alpm Entry",  v6_usage_cnt);

    return CTC_E_NONE;
}

int32
sys_nalpm2_dump_pfx_trie(uint8 lchip, uint16 vrfid, uint8 ip_ver)
{
    trie_dump_node_t dump_node;
    int32 ret = CTC_E_NONE;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 1. check valid */
    LCHIP_CHECK(lchip);
    SYS_NALPM2_INIT_CHECK;
    CTC_MAX_VALUE_CHECK(ip_ver, CTC_IP_VER_6);
    CTC_MAX_VALUE_CHECK(vrfid, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

    SYS_IPUC_LOCK;

    if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid])
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]---[%p] \r\n", __LINE__, &g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]);
        SYS_IPUC_UNLOCK;
        return ret;
    }

    if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        SYS_IPUC_UNLOCK;
        return ret;
    }

    /* 2. dump stats */
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP,"-----------prefix num:[%u]----total route[%u]------\n",
                        g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie->count,
                        g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrfid]);

    /* 3. dump trie */
    dump_node.father = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie;
    dump_node.root = g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie;
    dump_node.father_lvl = 0;

    ret = sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie, _sys_nalpm2_dump_pfx_trie_node, &dump_node, _TRIE_DUMP_TRAVERSE);

    SYS_IPUC_UNLOCK;
    return ret;
}

/* mode: 0->tcam; 1->sram; 2->by_route; 3->tree */
int32
sys_nalpm2_dump_route_trie(uint8 lchip, uint16 index, ctc_ipuc_param_t* p_ipuc_param, uint8 mode, uint8 detail, uint16 vrf_max)
{
    sys_nalpm2_dump_route_info_t dump;
    sys_nalpm2_info_tmp_t nalpm_info_tmp;
    sys_nalpm2_info_t* p_nalpm_info = (sys_nalpm2_info_t*)&nalpm_info_tmp;
    trie_dump_node_t dump_node;
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;

    LCHIP_CHECK(lchip);
    SYS_NALPM2_INIT_CHECK;
    CTC_MAX_VALUE_CHECK(vrf_max, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));
    CTC_MAX_VALUE_CHECK(p_ipuc_param->vrf_id, MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));
    CTC_IP_VER_CHECK(p_ipuc_param->ip_ver);

    SYS_IPUC_LOCK;

    /* 0. prepare data */
    sal_memset(&nalpm_info_tmp, 0, sizeof(sys_nalpm2_info_tmp_t));
    sal_memset(&dump, 0, sizeof(dump));

    vrf_max = vrf_max == 0 ? p_ipuc_param->vrf_id : vrf_max;
    ip_ver = p_ipuc_param->ip_ver;
    vrfid = p_ipuc_param->vrf_id;

    dump_node.lchip = lchip;
    dump_node.user_data = &dump;
    dump.detail = detail;
    dump.index = index;
    dump.mode = mode;

    /* 1. prepare mode 2 info */
    if (dump.mode == 2)
    {
        sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
        p_nalpm_info->route_masklen = p_ipuc_param->masklen;
        p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
        p_nalpm_info->ip_ver = ip_ver;

        dump.p_nalpm_info = p_nalpm_info;
    }

    /* 2. dump route trie */
    for (vrfid = p_ipuc_param->vrf_id; vrfid <= vrf_max; vrfid++)
    {
        if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]
            || NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie)
        {
            continue;
        }

        ret = sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie,
                                      _sys_nalpm2_dump_route_trie, &dump_node, _TRIE_DUMP_TRAVERSE);
    }

    SYS_IPUC_UNLOCK;
    return ret;
}

int32
sys_nalpm2_dump_db(uint8 lchip, sal_file_t p_f, ctc_global_dump_db_t* p_dump_param)
{
    uint32 i = 0;
    SYS_NALPM2_INIT_CHECK;
    SYS_DUMP_DB_LOG(p_f, "%s\n", "# NALPM");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "Master config:");
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Split mode", g_sys_nalpm2_master[lchip]->split_mode);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Nalpm opf type", g_sys_nalpm2_master[lchip]->opf_type_nalpm);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Ipsa enable", g_sys_nalpm2_master[lchip]->ipsa_enable);
    SYS_DUMP_DB_LOG(p_f, "%-30s: %u\n", "Auto frag arrange enable", g_sys_nalpm2_master[lchip]->frag_arrange_enable);
    SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    if (p_dump_param->detail)
    {
        SYS_DUMP_DB_LOG(p_f, "%s\n", "IPv4 route cnt per vrf:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-10s%-10s\n", "vrfid", "count");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        for(i = 0; i <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); i++)
        {
            if (0 == g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4][i])
            {
                continue;
            }
            SYS_DUMP_DB_LOG(p_f, "%-10u%-10u\n", i, g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_4][i]);
        }
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "IPv6 route cnt per vrf:");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        SYS_DUMP_DB_LOG(p_f, "%-10s%-10s\n", "vrfid", "count");
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
        for(i = 0; i <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID); i++)
        {
            if (0 == g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6][i])
            {
                continue;
            }
            SYS_DUMP_DB_LOG(p_f, "%-10u%-10u\n", i, g_sys_nalpm2_master[lchip]->vrf_route_cnt[CTC_IP_VER_6][i]);
        }
        SYS_DUMP_DB_LOG(p_f, "%s\n", "-----------------------------------------------------------------------------------");
    }
    sys_usw_opf_fprint_alloc_used_info(lchip, g_sys_nalpm2_master[lchip]->opf_type_nalpm, p_f);

    return CTC_E_NONE;
}

#define _________DB_Check_________

int32
sys_nalpm2_check_route(uint8 lchip, void *p_info, void* cb)
{
#ifdef IPUC_TEST_STUB
    uint32 * p_trie_key = NULL;
    uint8 ip_ver = 0;
    uint16 vrf_id = 0;
    trie_chk_info_t *info = (trie_chk_info_t *) p_info;

    ip_ver = info->ip_ver;
    vrf_id = info->vrf_id;

    //if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[ln][ip_ver][vrf_id])
    if(NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id])
    {
        return CTC_E_NOT_EXIST;
    }

    p_trie_key = mem_malloc2(MEM_IPUC_MODULE, IP_ADDR_SIZE(ip_ver), uint32);
    if(!p_trie_key)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_trie_key, 0 ,(IP_ADDR_SIZE(ip_ver)));
    sal_memcpy(p_trie_key, info->ip, (IP_ADDR_SIZE(ip_ver)));



   info->cb = _sys_nalpm2_dump_route_trie_node_l0;


    if(g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][vrf_id])
    {
        CTC_ERROR_RETURN(sys_trie_check_node(g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][vrf_id], p_trie_key,
                                            info->mask_len, (trie_check_cb_f)cb, (trie_chk_info_t *)info));
    }

    mem_free(p_trie_key);

#endif

    return 0;
}

int32
sys_nalpm2_dump_db_route_trie(uint8 lchip, uint8 ip_ver, uint16 vrf_id)
{
#ifdef IPUC_TEST_STUB

    trie_node_t *trie = NULL;
    trie_dump_node_t dump_node;

    trie = g_sys_nalpm2_master[lchip]->route_db_trie[ip_ver][vrf_id]->trie;

    dump_node.father = trie;
    dump_node.father_lvl = 0;
    dump_node.root =  trie;


    sys_nalpm_trie_traverse(trie, _sys_nalpm2_dump_route_trie_node_l0, &dump_node, _TRIE_DUMP_TRAVERSE);
#endif

    return 0;
}

#define _________WarmBoot_________

void
_sys_nalpm2_wb_mapping_ad_l0(sys_nalpm2_tcam_item_t* p_tcam_item, sys_wb_nalpm_prefix_info_t* p_wb_prefix_info, sys_nalpm2_tcam_ad_t* p_tcam_ad, uint8 is_sync)
{
    if (is_sync)
    {
        p_wb_prefix_info->tcam_idx = p_tcam_item->tcam_idx;
        p_wb_prefix_info->ad_route_masklen = p_tcam_item->p_l0_root_AD->masklen;
        p_wb_prefix_info->ip_ver = SYS_IPUC_VER(p_tcam_item->p_l0_root_AD);
        sal_memcpy(p_wb_prefix_info->ad_route_addr, &p_tcam_item->p_l0_root_AD->ip, IP_ADDR_SIZE(p_wb_prefix_info->ip_ver));
    }
    else
    {
        p_tcam_ad->tcam_idx = p_wb_prefix_info->tcam_idx;
        p_tcam_ad->masklen = p_wb_prefix_info->ad_route_masklen;
        sal_memcpy(p_tcam_ad->ip, p_wb_prefix_info->ad_route_addr, IP_ADDR_SIZE(p_wb_prefix_info->ip_ver));
    }

    return;
}

void
_sys_nalpm2_wb_mapping_ad_l1(sys_nalpm2_l0_item_t* p_l0_item, sys_wb_nalpm_pivot_info_t* p_wb_pivot_info, sys_nalpm2_l0_ad_t* p_l0_ad, uint8 is_sync)
{
    if (is_sync)
    {
        p_wb_pivot_info->sram_idx = p_l0_item->p_tcam_item->sram_idx;
        p_wb_pivot_info->snake_idx = p_l0_item->p_l1_root_info->hw_position[0];
        p_wb_pivot_info->entry_offset = p_l0_item->p_l1_root_info->hw_position[1];
        p_wb_pivot_info->sram_type = p_l0_item->p_tcam_item->sram_type;
        p_wb_pivot_info->ad_route_masklen = p_l0_item->p_l1_root_AD->masklen;
        p_wb_pivot_info->ip_ver = SYS_IPUC_VER(p_l0_item->p_l1_root_AD);
        sal_memcpy(p_wb_pivot_info->ad_route_addr, &p_l0_item->p_l1_root_AD->ip, IP_ADDR_SIZE(p_wb_pivot_info->ip_ver));
    }
    else
    {
        p_l0_ad->sram_idx = p_wb_pivot_info->sram_idx;
        p_l0_ad->snake_idx = p_wb_pivot_info->snake_idx;
        p_l0_ad->entry_offset = p_wb_pivot_info->entry_offset;
        p_l0_ad->sram_type = p_wb_pivot_info->sram_type;
        p_l0_ad->masklen = p_wb_pivot_info->ad_route_masklen;
        sal_memcpy(p_l0_ad->ip, p_wb_pivot_info->ad_route_addr, IP_ADDR_SIZE(p_wb_pivot_info->ip_ver));
    }

    return;
}

int32
__sys_nalpm2_wb_ad_sync_l0(trie_node_t * p_node, void * user_data)
{
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = (sys_nalpm2_trie_tcam_item_t* )p_node;
    sys_traverse_t *data = (sys_traverse_t *)user_data;
    ctc_wb_data_t *wb_data = (ctc_wb_data_t *)(data->data);
    sys_wb_nalpm_prefix_info_t  *p_wb_prefix_info;
    uint32 max_entry_cnt = 0;
#ifdef CTC_SHELL_DEBUG_ON
    uint8 lchip = data->value1;
#endif
    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if (p_node->type == INTERNAL)
    {
        return CTC_E_NONE;
    }

    if (!p_trie_tcam_item->tcam_item.p_l0_root_AD || !p_trie_tcam_item->tcam_item.p_l0_root_info->tcam_masklen)
    {
        return CTC_E_NONE;
    }

    max_entry_cnt = wb_data->buffer_len / (wb_data->key_len + wb_data->data_len);

    p_wb_prefix_info = (sys_wb_nalpm_prefix_info_t *)wb_data->buffer + wb_data->valid_cnt;

    sal_memset(p_wb_prefix_info, 0, sizeof(sys_wb_nalpm_prefix_info_t));
    p_wb_prefix_info->lchip = data->value1;

    _sys_nalpm2_wb_mapping_ad_l0(&p_trie_tcam_item->tcam_item, p_wb_prefix_info, NULL, 1);

    if (++wb_data->valid_cnt == max_entry_cnt)
    {
        CTC_ERROR_RETURN(ctc_wb_add_entry(wb_data));
        wb_data->valid_cnt = 0;
    }

    return CTC_E_NONE;
}

int32
__sys_nalpm2_wb_ad_sync_l1(trie_node_t * p_node, void * user_data)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = (sys_nalpm2_trie_l0_item_t* )p_node;
    sys_traverse_t *data = (sys_traverse_t *)user_data;
    ctc_wb_data_t *wb_data = (ctc_wb_data_t *)(data->data);
    sys_wb_nalpm_pivot_info_t  *p_wb_pivot_info;
    uint32 max_entry_cnt = 0;

    if (p_node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    if (!p_trie_l0_item->l0_item.p_l1_root_AD)
    {
        return CTC_E_NONE;
    }

    max_entry_cnt = wb_data->buffer_len / (wb_data->key_len + wb_data->data_len);

    p_wb_pivot_info = (sys_wb_nalpm_pivot_info_t *)wb_data->buffer + wb_data->valid_cnt;

    sal_memset(p_wb_pivot_info, 0, sizeof(sys_wb_nalpm_pivot_info_t));
    p_wb_pivot_info->lchip = data->value1;

    _sys_nalpm2_wb_mapping_ad_l1(&p_trie_l0_item->l0_item, p_wb_pivot_info, NULL, 1);

    if (++wb_data->valid_cnt == max_entry_cnt)
    {
        CTC_ERROR_RETURN(ctc_wb_add_entry(wb_data));
        wb_data->valid_cnt = 0;
    }

    return CTC_E_NONE;
}

int32
_sys_nalpm2_wb_ad_sync_l0(uint8 lchip, uint32 app_id, void *p_temp_wb_data)
{
    ctc_wb_data_t* p_wb_data = p_temp_wb_data;
    sys_traverse_t user_data;
    int32 ret = CTC_E_NONE;
    uint16 vrf_id = 0;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(NULL == g_sys_nalpm2_master[lchip])
    {
        return CTC_E_NONE;
    }

    if (app_id != 0 && CTC_WB_SUBID(app_id) != SYS_WB_APPID_IPUC_SUBID_INFO1)
    {
         return CTC_E_NONE;
    }

    CTC_WB_INIT_DATA_T(p_wb_data, sys_wb_nalpm_prefix_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);

    user_data.data = p_wb_data;
    p_wb_data->valid_cnt = 0;

    ip_ver = 0;
    do
    {
        vrf_id = 0;
        do
        {
            if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id])
            {
                vrf_id++;
                continue;
            }

            user_data.value1 = lchip;
            CTC_ERROR_RETURN(sys_nalpm_trie_traverse (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]->trie,
                                   __sys_nalpm2_wb_ad_sync_l0, (void *)&user_data, _TRIE_PREORDER_TRAVERSE));

            vrf_id++;

        } while (vrf_id <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    if (p_wb_data->valid_cnt > 0)
    {
        CTC_ERROR_GOTO(ctc_wb_add_entry(p_wb_data), ret, done);
    }

    CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);

done:

    return ret;
}

int32
_sys_nalpm2_wb_ad_sync_l1(uint8 lchip, uint32 app_id, void *p_temp_wb_data)
{
    ctc_wb_data_t* p_wb_data = p_temp_wb_data;
    sys_traverse_t user_data;
    int32 ret = CTC_E_NONE;
    uint16 vrf_id = 0;
    uint8 ip_ver = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    if(NULL == g_sys_nalpm2_master[lchip])
    {
        return CTC_E_NONE;
    }

    if (app_id != 0 && CTC_WB_SUBID(app_id) != SYS_WB_APPID_IPUC_SUBID_INFO1)
    {
         return CTC_E_NONE;
    }

    CTC_WB_INIT_DATA_T(p_wb_data, sys_wb_nalpm_pivot_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_PIVOT);

    user_data.data = p_wb_data;
    p_wb_data->valid_cnt = 0;

    ip_ver = 0;
    do
    {
        vrf_id = 0;
        do
        {
            if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id])
            {
                vrf_id++;
                continue;
            }

            user_data.value1 = lchip;
            CTC_ERROR_RETURN(sys_nalpm_trie_traverse (g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]->trie,
                                   __sys_nalpm2_wb_ad_sync_l1, (void *)&user_data, _TRIE_PREORDER_TRAVERSE));

            vrf_id++;

        } while (vrf_id <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    if (p_wb_data->valid_cnt > 0)
    {
        CTC_ERROR_GOTO(ctc_wb_add_entry(p_wb_data), ret, done);
    }

    CTC_WB_SYNC_END_DATA(CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_PIVOT);

done:

    return ret;
}

int32
_sys_nalpm2_wb_restore_l0(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_info_t* p_nalpm_info)
{
    sys_nalpm2_route_store_info_t lkp_rlt;
    sys_nalpm2_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    sys_nalpm2_trie_l0_info_t* p_trie_l0_info = NULL;
    sys_nalpm2_trie_tcam_item_t *p_trie_tcam_item;
    sys_nalpm2_trie_l0_item_t *p_trie_l0_item;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_info_t* p_l0_root_info= NULL;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_l0_item_t* p_l0_item_best = NULL;
    sys_nalpm2_l0_item_t* l0_item_temp[SYS_NALPM2_MAX_SNACKE_L0][ROUTE_NUM_PER_SNAKE_V4_L0];
    sys_nalpm2_info_tmp_t* l0_info_temp[SYS_NALPM2_MAX_SNACKE_L0][ROUTE_NUM_PER_SNAKE_V4_L0];
    sys_ipuc_info_t l1_info_temp;
    uint32 DsNeoLpmMemorySnake0[12] = {0};
    void* ptr_l0 = DsNeoLpmMemorySnake0;
    sys_ipuc_tcam_key_t tcam_key;
    sys_ipuc_tcam_ad_t tcam_ad;
    sys_usw_opf_t opf;
    uint32 key_l00[4] = {0};
    uint32 key_l11[4] = {0};
    uint32 key_l0[4] = {0};
    uint32 ip_null[4] = {0};
    uint32 ip_temp[4] = {0};
    int32 ret = CTC_E_NONE;
    uint32 tbl_id1 = 0;
    uint32 tbl_id = 0;
    uint32 hw_idx = 0;
    uint32 cmd = 0;
    uint16 tcam_idx = p_sys_ipuc_param->info->tcam_idx;
    uint16 vrf_id = p_sys_ipuc_param->info->vrf_id;
    uint8 ip_ver = p_nalpm_info->ip_ver;
    uint8 route_per_snake_l0 = 0;
    uint8 snake_idx_l0 = 0;
    uint8 entry_idx_l0 = 0;
    uint8 best_route_mask = 0;
    uint8 msl = ((ip_ver == CTC_IP_VER_4) ? SYS_NALPM2_V4_MASK_LEN_MAX : SYS_NALPM2_V6_MASK_LEN_MAX);
    uint8 i = 0;
    uint8 j = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /* 0. prepare data */
    p_trie_tcam_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_tcam_item_t), sys_nalpm2_trie_tcam_item_t);
    if(NULL == p_trie_tcam_item)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return CTC_E_NO_MEMORY;
    }

    p_l0_root_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_l0_root_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        ret = CTC_E_NO_MEMORY;
        goto error0;
    }

    i = 0;
    do
    {
        j = 0;
        do
        {
            l0_item_temp[i][j] = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm2_l0_item_t));
            if (NULL == l0_item_temp[i][j])
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                ret = CTC_E_NO_MEMORY;
                goto error1;
            }
            sal_memset(l0_item_temp[i][j], 0, sizeof(sys_nalpm2_l0_item_t));

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);

    i = 0;
    do
    {
        j = 0;
        do
        {
            l0_info_temp[i][j] = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm2_info_tmp_t));
            if (NULL == l0_info_temp[i][j])
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                ret = CTC_E_NO_MEMORY;
                goto error2;
            }
            sal_memset(l0_info_temp[i][j], 0, sizeof(sys_nalpm2_info_tmp_t));

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);

    sal_memset(p_trie_tcam_item, 0, sizeof(sys_nalpm2_trie_tcam_item_t));
    sal_memset(p_lkp_rlt, 0, sizeof(sys_nalpm2_route_store_info_t));
    sal_memset(p_l0_root_info, 0, NALPM2_INFO_SIZE(ip_ver));
    sal_memset(&tcam_key, 0, sizeof(sys_ipuc_tcam_key_t));
    sal_memset(&tcam_ad, 0, sizeof(sys_ipuc_tcam_ad_t));
    sal_memset(&l1_info_temp, 0, sizeof(sys_ipuc_info_t));
    sal_memset(&opf, 0, sizeof(sys_usw_opf_t));

    /* 1. init prefix trie */
    if (g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id] == 0)
    {
        CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]), ret, error2);
        CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]), ret, error3);
    }

    /* 2. lookup prefix trie and check whether has tcam prefix */
    _sys_nalpm2_route_lkp_l0(lchip, p_nalpm_info, p_lkp_rlt);
    if (p_lkp_rlt->tcam_hit && p_lkp_rlt->p_l0_item && p_lkp_rlt->p_tcam_item->tcam_idx == tcam_idx)
    {
        /* 2.1 is default route */
        if (p_sys_ipuc_param->info->masklen == 0)
        {
            g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
            goto error2;
        }/* /0 route may not hit tcam, because root node is not a payload when /0 route is not insert*/

        /* 2.2 restore route info */
        CTC_ERROR_GOTO(_sys_nalpm2_wb_restore_l1(lchip, p_sys_ipuc_param, p_lkp_rlt->p_l0_item), ret, error4);

        goto error2;
    }

    /* 3. read tcam */
    tcam_key.key_idx = tcam_idx;
    tcam_ad.tcamAd_key_idx = tcam_idx;
    sys_tsingma_ipuc_tcam_read_key(lchip, ip_ver, SYS_PRIVATE_MODE, &tcam_key);
    sys_tsingma_ipuc_tcam_read_ad(lchip, ip_ver, SYS_PRIVATE_MODE, &tcam_ad);

    /* 3. restore tcam item */
    p_tcam_item = &p_trie_tcam_item->tcam_item;

    p_tcam_item->tcam_idx = tcam_idx;
    p_tcam_item->sram_idx = tcam_ad.pointer;
    p_tcam_item->p_l0_root_info = p_l0_root_info;
    _sys_nalpm2_set_sram_type_l0(lchip, ip_ver, p_sys_ipuc_param->info->masklen, p_tcam_item);
    CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &(p_tcam_item->trie)), ret, error4);

    /* 4. restore l0 root info */
    p_l0_root_info->ad_idx = tcam_ad.nexthop;
    p_l0_root_info->ip_ver = ip_ver;
    p_l0_root_info->vrf_id = vrf_id;
    p_l0_root_info->tcam_masklen = tcam_key.mask_len;
    sal_memcpy(p_l0_root_info->ip, &tcam_key.ip, IP_ADDR_SIZE(ip_ver));

    ret = _sys_nalpm2_tcam_idx_alloc(lchip, &p_sys_ipuc_param->param, p_tcam_item);
    if (ret)
    {
        goto error4;
    }

    /* 5. insert l0 prefix trie */
    sal_memcpy(key_l00, p_tcam_item->p_l0_root_info->ip, IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key_l00);
    SYS_NALPM_CONVERT_TO_LSB(key_l00, p_tcam_item->p_l0_root_info->tcam_masklen, ip_ver);
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id], key_l00, NULL, p_tcam_item->p_l0_root_info->tcam_masklen, (trie_node_t *)p_trie_tcam_item, 0), ret, error5);

    NALPM2_BUCKET_L0(lchip).bkt_cnt++;
    NALPM2_BUCKET_L0(lchip).bkt_usage[NALPM2_FORMAT(lchip, ip_ver)]++;

    /* 6. restore l0 opf index */
    opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;
    opf.pool_index = LEVEL0;
    opf.multiple = 1;
    sys_usw_opf_alloc_offset_from_position(lchip, &opf, 1, p_tcam_item->sram_idx);

    /* 7. loop and restore l0 item */
    route_per_snake_l0 = _sys_nalpm2_get_snake_route_num_l0(lchip, p_tcam_item->sram_type);
    snake_idx_l0 = 0;
    do
    {
        /* 7.1 read l0 sram */
        _sys_nalpm2_get_table_id_l0(lchip, p_tcam_item->sram_type, snake_idx_l0, &tbl_id, &tbl_id1);
        hw_idx = NALPM2_HW_SRAM_INDEX_L0(lchip, p_tcam_item->sram_idx, snake_idx_l0);
        cmd = DRV_IOR(tbl_id, DRV_ENTRY_FLAG);
        DRV_IOCTL(lchip, hw_idx, cmd, ptr_l0);

        /* 7.2 restore l0 item */
        entry_idx_l0 = 0;
        do
        {
            /* 7.2.1 decode l0 sram */
            l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.p_l0_item = l0_item_temp[snake_idx_l0][entry_idx_l0];
            _sys_nalpm2_decode_sram_l0(lchip, p_tcam_item, (sys_nalpm2_info_t *)l0_info_temp[snake_idx_l0][entry_idx_l0], entry_idx_l0, ptr_l0);

            /* 7.2.2 restore valid l0 item */
            if (l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.ad_idx && NULL == p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0])
            {
                /* 7.2.2.1 prepare data */
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0] = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
                if (NULL == p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0])
                {
                    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                    ret = CTC_E_NO_MEMORY;
                    goto error6;
                }

                p_trie_l0_item = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_item_t), sys_nalpm2_trie_l0_item_t);
                if(NULL == p_trie_l0_item)
                {
                    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                    ret = CTC_E_NO_MEMORY;
                    goto error6;
                }

                p_trie_l0_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l0_info_t), sys_nalpm2_trie_l0_info_t);
                if (NULL == p_trie_l0_info)
                {
                    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
                    ret = CTC_E_NO_MEMORY;
                    goto error6;
                }

                sal_memset(p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0], 0, NALPM2_INFO_SIZE(ip_ver));
                sal_memset(p_trie_l0_item, 0, sizeof(sys_nalpm2_trie_l0_item_t));
                sal_memset(p_trie_l0_info, 0, sizeof(sys_nalpm2_trie_l0_info_t));

                sal_memcpy(&p_trie_l0_item->l0_item, l0_item_temp[snake_idx_l0][entry_idx_l0], sizeof(sys_nalpm2_l0_item_t));
                sal_memcpy(p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0], l0_info_temp[snake_idx_l0][entry_idx_l0], NALPM2_INFO_SIZE(ip_ver));

                /* 7.2.2.2 restore l0 info */
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->p_l0_item = &p_trie_l0_item->l0_item;
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->hw_position[0] = snake_idx_l0;
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->hw_position[1] = entry_idx_l0;
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->vrf_id = vrf_id;
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->ip_ver = ip_ver;
                p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->tcam_masklen = p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->route_masklen;

                /* 7.2.2.3 insert l0 info trie */
                p_trie_l0_info->p_l0_info = p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0];
                sal_memcpy(key_l0, p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->ip, IP_ADDR_SIZE(ip_ver));
                SYS_IPV6_IP_SORT(ip_ver, key_l0);
                CTC_ERROR_GOTO(sys_nalpm_trie_insert(p_tcam_item->trie, key_l0, NULL, p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0]->route_masklen, (trie_node_t *) p_trie_l0_info, 1), ret, error6);

                /* 7.2.2.4 restore l0 item */
                p_l0_item = &p_trie_l0_item->l0_item;

                p_l0_item->tcam_idx = tcam_idx;
                p_l0_item->p_tcam_item = p_tcam_item;
                p_l0_item->p_l1_root_info = p_tcam_item->p_l0_info_array[snake_idx_l0][entry_idx_l0];
                _sys_nalpm2_set_sram_type_l1(lchip, ip_ver, p_sys_ipuc_param->info->masklen, p_l0_item);
                CTC_ERROR_GOTO(sys_nalpm_trie_init(msl, &(p_l0_item->trie)), ret, error6);

                /* 7.2.2.4 insert l1 prefix trie */
                sal_memcpy(key_l11, p_l0_item->p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver));
                SYS_IPV6_IP_SORT(ip_ver, key_l11);
                SYS_NALPM_CONVERT_TO_LSB(key_l11, p_l0_item->p_l1_root_info->route_masklen, ip_ver);
                CTC_ERROR_GOTO(sys_nalpm_trie_insert(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id], key_l11, NULL, p_l0_item->p_l1_root_info->route_masklen, (trie_node_t *)p_trie_l0_item, 0), ret, error6);

                /* 7.2.2.5 restore l0 bucket */
                _sys_nalpm2_bucket_list_update_l0(lchip, p_tcam_item->sram_idx, 1);
                CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).bitmap[snake_idx_l0], entry_idx_l0);
                g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL0][ip_ver]++;

                NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).sram_idx = p_tcam_item->sram_idx;
                NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).fmt = NALPM2_FORMAT(lchip, ip_ver);
                NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).p_tcam_item[p_tcam_item->sub_bkt] = p_tcam_item;
                if (!sal_memcmp(ip_null, p_tcam_item->p_l0_root_info->ip, IP_ADDR_SIZE(ip_ver)))
                {
                    NALPM2_BUCKET_ARRAY_L0(lchip, p_tcam_item->sram_idx).is_root = 1;
                }

                /* 7.2.2.6 restore l1 bucket */
                if (!NALPM2_BUCKET_SUB_BKT_L1(lchip, p_l0_item->sram_idx))
                {
                    NALPM2_BUCKET_L1(lchip).bkt_cnt++;
                    NALPM2_BUCKET_L1(lchip).bkt_usage[NALPM2_FORMAT(lchip, ip_ver)]++;
                }

                NALPM2_BUCKET_SUB_BKT_L1(lchip, p_l0_item->sram_idx) = MAX(NALPM2_BUCKET_SUB_BKT_L1(lchip, p_l0_item->sram_idx), p_l0_item->sub_bkt + 1);
                NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).p_l0_item[p_l0_item->sub_bkt] = p_l0_item;
                NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).sram_idx = p_l0_item->sram_idx;
                NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).fmt = NALPM2_FORMAT(lchip, ip_ver);
                if (!sal_memcmp(ip_null, p_l0_item->p_l1_root_info->ip, IP_ADDR_SIZE(ip_ver)))
                {
                    NALPM2_BUCKET_ARRAY_L1(lchip, p_l0_item->sram_idx).is_root = 1;
                }

                /* 7.2.2.7 restore l1 opf index */
                sal_memset(&opf, 0, sizeof(sys_usw_opf_t));
                opf.pool_type = g_sys_nalpm2_master[lchip]->opf_type_nalpm;
                opf.pool_index = LEVEL1;
                opf.multiple = 1;
                sys_usw_opf_alloc_offset_from_position(lchip, &opf, 1, p_l0_item->sram_idx);

                /* 7.2.2.8 compare and find longest prefix */
                sal_memcpy(ip_temp, p_nalpm_info->ip, IP_ADDR_SIZE(ip_ver));
                SYS_NALPM2_IP_ADDR_MASK(ip_temp, l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.route_masklen, ip_ver);

                if (p_nalpm_info->route_masklen >= l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.route_masklen &&
                    !sal_memcmp(l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.ip, ip_temp, IP_ADDR_SIZE(ip_ver)) &&
                    l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.route_masklen >= best_route_mask)
                {
                    best_route_mask = l0_info_temp[snake_idx_l0][entry_idx_l0]->nalpm2_info.route_masklen;
                    p_l0_item_best = p_l0_item;
                }
            }

            entry_idx_l0++;

        } while (entry_idx_l0 < route_per_snake_l0);

        snake_idx_l0++;

    } while (snake_idx_l0 < NALPM2_BUKCET_SNAKE_NUM_L0(lchip));

    /* 8. restore route info whether sram index and sub bucket equal to l0 item */
    if (NULL == p_l0_item_best->p_l1_info_array[p_sys_ipuc_param->info->snake_idx][p_sys_ipuc_param->info->entry_offset] &&
        p_sys_ipuc_param->info->sram_idx == p_l0_item_best->sram_idx &&
        p_sys_ipuc_param->info->sub_bkt == p_l0_item_best->sub_bkt &&
        p_sys_ipuc_param->info->masklen)
    {
        /* 8.1 restore route info */
        CTC_ERROR_GOTO(_sys_nalpm2_wb_restore_l1(lchip, p_sys_ipuc_param, p_l0_item_best), ret, error6);
    }
    else if (p_sys_ipuc_param->info->masklen == 0)
    {
        g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
    }

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (l0_info_temp[i][j])
            {
                mem_free(l0_info_temp[i][j]);
                l0_info_temp[i][j] = NULL;
            }

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (l0_item_temp[i][j])
            {
                mem_free(l0_item_temp[i][j]);
                l0_item_temp[i][j] = NULL;
            }

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);

    return ret;

error6:
    sys_nalpm_trie_delete(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id], key_l00, p_tcam_item->p_l0_root_info->tcam_masklen, (trie_node_t **)&p_trie_tcam_item, 0);
error5:
    sys_nalpm_trie_destroy(p_tcam_item->trie);
    p_tcam_item->trie = NULL;
error4:
    sys_nalpm_trie_destroy(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id]);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrf_id] = NULL;
error3:
    sys_nalpm_trie_destroy(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]);
    g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id] = NULL;
error2:
    i = 0;
    do
    {
        j = 0;
        do
        {
            if (l0_info_temp[i][j])
            {
                mem_free(l0_info_temp[i][j]);
                l0_info_temp[i][j] = NULL;
            }

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);
error1:
    i = 0;
    do
    {
        j = 0;
        do
        {
            if (l0_item_temp[i][j])
            {
                mem_free(l0_item_temp[i][j]);
                l0_item_temp[i][j] = NULL;
            }

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L0);

        i++;

    } while (i < SYS_NALPM2_MAX_SNACKE_L0);

    if (p_l0_root_info)
    {
        mem_free(p_l0_root_info);
    }
error0:
    if (p_trie_tcam_item)
    {
        mem_free(p_trie_tcam_item);
    }

    return ret;
}


int32
_sys_nalpm2_wb_restore_l1(uint8 lchip, sys_ipuc_param_t* p_sys_ipuc_param, sys_nalpm2_l0_item_t* p_l0_item)
{
    sys_ipuc_info_t* p_l1_info = p_sys_ipuc_param->info;
    sys_nalpm2_trie_l1_info_t* p_trie_l1_info;
    uint32 key_l1[4] = {0};
    int32 ret = CTC_E_NONE;
    uint16 vrf_id = p_l0_item->p_l1_root_info->vrf_id;
    uint16 sram_idx = p_l0_item->sram_idx;
    uint8 ip_ver = p_l0_item->p_l1_root_info->ip_ver;
    uint8 snake_idx = p_sys_ipuc_param->info->snake_idx;
    uint8 entry_offset = p_sys_ipuc_param->info->entry_offset;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    p_trie_l1_info = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_trie_l1_info_t), sys_nalpm2_trie_l1_info_t);
    if (NULL == p_trie_l1_info)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_trie_l1_info, 0, sizeof(sys_nalpm2_trie_l1_info_t));

    p_l0_item->p_l1_info_array[snake_idx][entry_offset] = p_l1_info;
    p_trie_l1_info->p_l1_info = p_l1_info;

    sal_memcpy(key_l1, &(p_l1_info->ip), IP_ADDR_SIZE(ip_ver));
    SYS_IPV6_IP_SORT(ip_ver, key_l1);
    CTC_ERROR_GOTO(sys_nalpm_trie_insert(p_l0_item->trie, key_l1, NULL, p_l1_info->masklen, (trie_node_t *)p_trie_l1_info, 1), ret, error0);

    _sys_nalpm2_bucket_list_update_l1(lchip, sram_idx, 1);
    CTC_BIT_SET(NALPM2_BUCKET_ARRAY_L1(lchip, sram_idx).bitmap[snake_idx], entry_offset);

    g_sys_nalpm2_master[lchip]->vrf_route_cnt[ip_ver][vrf_id]++;
    g_sys_nalpm2_master[lchip]->route_stats[ip_ver][SYS_IPUC_ALPM]++;
    g_sys_nalpm2_master[lchip]->ln_entry_cnt[LEVEL1][ip_ver]++;

    return ret;

error0:
    if (p_trie_l1_info)
    {
        mem_free(p_trie_l1_info);
    }

    return ret;
}

int32
_sys_nalpm2_wb_ad_restore_l0(uint8 lchip)
{
    sys_wb_nalpm_prefix_info_t wb_prefix_info;
    sys_nalpm2_tcam_ad_t* p_tcam_ad = NULL;
    ctc_wb_query_t wb_query;
    int32 ret = CTC_E_NONE;
    uint32 entry_cnt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&wb_query, 0, sizeof(ctc_wb_query_t));
    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);

    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_nalpm_prefix_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_INFO1);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));

    sal_memcpy(&wb_prefix_info, (sys_wb_nalpm_prefix_info_t *)wb_query.buffer + entry_cnt++, wb_query.key_len + wb_query.data_len);

    p_tcam_ad = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_tcam_ad_t), sys_nalpm2_tcam_ad_t);
    if (NULL == p_tcam_ad)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_tcam_ad, 0, sizeof(sys_nalpm2_tcam_ad_t));

    _sys_nalpm2_wb_mapping_ad_l0(NULL, &wb_prefix_info, p_tcam_ad, 0);

    if (NULL == ctc_hash_insert(g_sys_nalpm2_master[wb_prefix_info.lchip]->ipuc_cover_hash[LEVEL0], p_tcam_ad))
    {
        goto error_proc;
    }

    CTC_WB_QUERY_ENTRY_END((&wb_query));

    goto done;

error_proc:
    if (p_tcam_ad)
    {
        mem_free(p_tcam_ad);
    }

done:
    if (wb_query.key)
    {
        mem_free(wb_query.key);
    }

    CTC_WB_FREE_BUFFER(wb_query.buffer)

    return ret;
}

int32
_sys_nalpm2_wb_ad_restore_l1(uint8 lchip)
{
    sys_wb_nalpm_pivot_info_t wb_pivot_info;
    sys_nalpm2_l0_ad_t* p_l0_ad = NULL;
    ctc_wb_query_t wb_query;
    int32 ret = CTC_E_NONE;
    uint32 entry_cnt = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    sal_memset(&wb_query, 0, sizeof(ctc_wb_query_t));
    CTC_WB_ALLOC_BUFFER(&wb_query.buffer);

    CTC_WB_INIT_QUERY_T((&wb_query), sys_wb_nalpm_pivot_info_t, CTC_FEATURE_IPUC, SYS_WB_APPID_IPUC_SUBID_PIVOT);
    CTC_WB_QUERY_ENTRY_BEGIN((&wb_query));

    sal_memcpy(&wb_pivot_info, (sys_wb_nalpm_pivot_info_t *)wb_query.buffer + entry_cnt++, wb_query.key_len + wb_query.data_len);

    p_l0_ad = mem_malloc2(MEM_IPUC_MODULE, sizeof(sys_nalpm2_l0_ad_t), sys_nalpm2_l0_ad_t);
    if (NULL == p_l0_ad)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_l0_ad, 0, sizeof(sys_nalpm2_l0_ad_t));

    _sys_nalpm2_wb_mapping_ad_l1(NULL, &wb_pivot_info, p_l0_ad, 0);

    if (NULL == ctc_hash_insert(g_sys_nalpm2_master[wb_pivot_info.lchip]->ipuc_cover_hash[LEVEL1], p_l0_ad))
    {
        goto error_proc;
    }

    CTC_WB_QUERY_ENTRY_END((&wb_query));

    goto done;

error_proc:
    if (p_l0_ad)
    {
        mem_free(p_l0_ad);
    }

done:
    if (wb_query.key)
    {
        mem_free(wb_query.key);
    }

    CTC_WB_FREE_BUFFER(wb_query.buffer)

    return ret;
}


int32
_sys_nalpm2_wb_traverse_route_trie(trie_node_t* node, void* data)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = (sys_nalpm2_trie_l0_item_t*)node;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    int32 ret = CTC_E_NONE;
    uint16 tcam_index = 0;
    uint8 lchip = 0;
    uint8 i, j;

    if (node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    p_l0_item = &p_trie_l0_item->l0_item;
    if (p_l0_item->p_tcam_item)
    {
        tcam_index = p_l0_item->p_tcam_item->tcam_idx;
    }

    i = 0;
    do
    {
        j = 0;
        do
        {
            if (NULL == p_l0_item->p_l1_info_array[i][j])
            {
                j++;
                continue;
            }

            p_l0_item->p_l1_info_array[i][j]->tcam_idx = tcam_index;

            j++;

        } while (j < ROUTE_NUM_PER_SNAKE_V4_L1);

        i++;

    } while (i < NALPM2_BUKCET_SNAKE_NUM_L1(lchip));

    return ret;
}

int32
_sys_nalpm2_wb_traverse_set_ad_l0(trie_node_t* node, void* data)
{
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = (sys_nalpm2_trie_tcam_item_t*)node;
    trie_dump_node_t* p_dump_node = (trie_dump_node_t*)data;
    sys_nalpm2_tcam_item_t* p_tcam_item = NULL;
    sys_nalpm2_tcam_ad_t* p_tcam_ad = NULL;
    sys_nalpm2_tcam_ad_t tcam_ad = {0};
    sys_ipuc_info_t ipuc_info = {0};
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;
    uint8 lchip = p_dump_node->lchip;

    if (node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    p_tcam_item = &p_trie_tcam_item->tcam_item;
    ip_ver = p_tcam_item->p_l0_root_info->ip_ver;

    tcam_ad.tcam_idx = p_tcam_item->tcam_idx;
    p_tcam_ad = ctc_hash_lookup(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL0], &tcam_ad);
    if (NULL == p_tcam_ad)
    {
        return ret;
    }

    sal_memcpy(&(ipuc_info.ip), p_tcam_ad->ip, IP_ADDR_SIZE(ip_ver));
    ipuc_info.masklen = p_tcam_ad->masklen;
    ipuc_info.vrf_id = p_tcam_item->p_l0_root_info->vrf_id;
    if (IS_MAX_MASKLEN(ip_ver, p_tcam_ad->masklen))
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_HOST_USE_LPM);
    }
    p_tcam_item->p_l0_root_AD = ctc_hash_lookup(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], &ipuc_info);

    return ret;
}

int32
_sys_nalpm2_wb_traverse_set_ad_l1(trie_node_t* node, void* data)
{
    sys_nalpm2_trie_l0_item_t* p_trie_l0_item = (sys_nalpm2_trie_l0_item_t*)node;
    trie_dump_node_t* p_dump_node = (trie_dump_node_t*)data;
    sys_nalpm2_l0_item_t* p_l0_item = NULL;
    sys_nalpm2_l0_ad_t* p_l0_ad = NULL;
    sys_nalpm2_l0_ad_t l0_ad = {0};
    sys_ipuc_info_t ipuc_info = {0};
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;
    uint8 lchip = p_dump_node->lchip;

    if (node->type == INTERNAL)
    {
         return CTC_E_NONE;
    }

    p_l0_item = &p_trie_l0_item->l0_item;
    ip_ver = p_l0_item->p_l1_root_info->ip_ver;

    l0_ad.sram_idx = p_l0_item->p_tcam_item->sram_idx;
    l0_ad.snake_idx = p_l0_item->p_l1_root_info->hw_position[0];
    l0_ad.entry_offset = p_l0_item->p_l1_root_info->hw_position[1];
    l0_ad.sram_type = p_l0_item->p_tcam_item->sram_type;

    p_l0_ad = ctc_hash_lookup(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL1], &l0_ad);
    if (NULL == p_l0_ad)
    {
        return ret;
    }

    sal_memcpy(&(ipuc_info.ip), p_l0_ad->ip, IP_ADDR_SIZE(ip_ver));
    ipuc_info.masklen = p_l0_ad->masklen;
    ipuc_info.vrf_id = p_l0_item->p_l1_root_info->vrf_id;
    if (IS_MAX_MASKLEN(ip_ver, p_l0_ad->masklen))
    {
        CTC_SET_FLAG(ipuc_info.route_flag, SYS_IPUC_FLAG_HOST_USE_LPM);
    }
    p_l0_item->p_l1_root_AD = ctc_hash_lookup(p_usw_ipuc_master[lchip]->fib_hash[ip_ver], &ipuc_info);

    return ret;
}


int32
sys_nalpm2_wb_set_tcam_index(uint8 lchip)
{
    trie_dump_node_t dump_node = {0};
    sys_nalpm2_trie_tcam_item_t* p_trie_tcam_item = NULL;
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;

    ip_ver = 0;
    do
    {
        vrfid = 0;
        do
        {

            if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid] ||
                NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]->trie)
            {
                vrfid++;
                continue;
            }

            ret = sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]->trie,
                                      _sys_nalpm2_wb_traverse_route_trie, &dump_node, _TRIE_DUMP_TRAVERSE);

            /* update tcam idx of /0 route info ,for ofb may change tcam idx of tcam item */
            p_trie_tcam_item = CONTAINER_OF(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie, sys_nalpm2_trie_tcam_item_t, node);
            if(p_trie_tcam_item->tcam_item.p_l0_root_AD)
            {
                p_trie_tcam_item->tcam_item.p_l0_root_AD->tcam_idx = p_trie_tcam_item->tcam_item.tcam_idx;
            }
            vrfid++;

        } while (vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    return ret;
}

int32
sys_nalpm2_wb_set_ad_info(uint8 lchip)
{
    trie_dump_node_t dump_node = {0};
    int32 ret = CTC_E_NONE;
    uint16 vrfid = 0;
    uint8 ip_ver = 0;

    dump_node.lchip = lchip;

    ip_ver = 0;
    do
    {
        vrfid = 0;
        do
        {

            if (NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid] ||
                NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie ||
                NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid] ||
                NULL == g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]->trie)
            {
                vrfid++;
                continue;
            }

            ret = sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrfid]->trie,
                                      _sys_nalpm2_wb_traverse_set_ad_l0, &dump_node, _TRIE_DUMP_TRAVERSE);

            ret = sys_nalpm_trie_traverse(g_sys_nalpm2_master[lchip]->prefix_trie[LEVEL1][ip_ver][vrfid]->trie,
                                      _sys_nalpm2_wb_traverse_set_ad_l1, &dump_node, _TRIE_DUMP_TRAVERSE);

            vrfid++;

        } while (vrfid <= MCHIP_CAP(SYS_CAP_SPEC_MAX_VRFID));

        ip_ver++;

    } while (ip_ver < MAX_CTC_IP_VER);

    ctc_hash_traverse(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL0], (hash_traversal_fn)_sys_nalpm2_hash_free_node_data, &lchip);
    ctc_hash_traverse(g_sys_nalpm2_master[lchip]->ipuc_cover_hash[LEVEL1], (hash_traversal_fn)_sys_nalpm2_hash_free_node_data, &lchip);

    return ret;
}

int32
sys_nalpm2_wb_prefix_sync(uint8 lchip, uint32 app_id, void *p_temp_wb_data)
{
    _sys_nalpm2_wb_ad_sync_l0(lchip, app_id, p_temp_wb_data);
    _sys_nalpm2_wb_ad_sync_l1(lchip, app_id, p_temp_wb_data);

    return CTC_E_NONE;
}

int32
sys_nalpm2_wb_prefix_restore(uint8 lchip)
{
    _sys_nalpm2_wb_ad_restore_l0(lchip);
    _sys_nalpm2_wb_ad_restore_l1(lchip);

    return CTC_E_NONE;
}

#define _________Invalid_Code_________

#if 0
int32
sys_nalpm2_wb_get_info(uint8 lchip, void* p_ipuc_param_v, void* p_alpm_info)
{
    sys_wb_nalpm_info_t* p_wb_nalpm_info = (sys_wb_nalpm_info_t*)p_alpm_info;
    sys_nalpm2_info_t*  p_nalpm_info = NULL;
    sys_nalpm2_route_store_info_t lkp_rlt;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    ctc_ipuc_param_t* p_ipuc_param = (ctc_ipuc_param_t*)p_ipuc_param_v;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_NALPM2_INIT_CHECK;

    ip_ver = p_ipuc_param->ip_ver;
    p_nalpm_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm2_info_t);
    if(NULL == p_nalpm_info)
    {
        return CTC_E_NO_MEMORY;
    }
    sal_memset(p_nalpm_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));
    p_nalpm_info->ip_ver = ip_ver;
    sal_memcpy(p_nalpm_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_nalpm_info->route_masklen = p_ipuc_param->masklen;
    p_nalpm_info->vrf_id = p_ipuc_param->vrf_id;
    //SYS_IP_V6_SORT(p_nalpm_info);

    sal_memset(&lkp_rlt, 0 , sizeof(sys_nalpm2_route_store_info_t));
    ret = _sys_nalpm2_route_lkp_l0(lchip, p_nalpm_info, &lkp_rlt);
    mem_free(p_nalpm_info);
    if(!lkp_rlt.tcam_hit || lkp_rlt.p_tcam_item == NULL)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- tcam not hit\r\n", __LINE__);
        return CTC_E_NOT_EXIST;
    }
    if(!lkp_rlt.sram_hit && p_ipuc_param->masklen > 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- sram not hit\r\n", __LINE__);
        return  CTC_E_NOT_EXIST;
    }

    p_wb_nalpm_info->sram_idx = lkp_rlt.p_tcam_item->sram_idx;
    p_wb_nalpm_info->sub_bkt = lkp_rlt.p_tcam_item->sub_bkt;
    p_wb_nalpm_info->snake_idx = lkp_rlt.snake_idx[0];
    p_wb_nalpm_info->entry_offset = lkp_rlt.entry_offset[0];

    return ret;
}

STATIC int32
_sys_nalpm2_get_bucket_entry_cnt(uint8 lchip, uint8 ln, uint8 sram_type)
{
    uint32 count = 0;

    switch(sram_type)
    {
    case SYS_NALPM2_SRAM_TYPE_V4_32:
    case SYS_NALPM2_SRAM_TYPE_V4_EXT:
        count = NALPM2_BUCKET_DB(lchip, ln).snake_fmt_num[NALPM2_FMT_V4]*NALPM2_BUKCET_SNAKE_NUM(lchip, ln);
        break;
    case SYS_NALPM2_SRAM_TYPE_V6_64:
        count = NALPM2_BUCKET_DB(lchip, ln).snake_fmt_num[NALPM2_FMT_V6_64]*NALPM2_BUKCET_SNAKE_NUM(lchip, ln);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    case SYS_NALPM2_SRAM_TYPE_V6_128:
        count = NALPM2_BUCKET_DB(lchip, ln).snake_fmt_num[NALPM2_FMT_V6_128]*NALPM2_BUKCET_SNAKE_NUM(lchip, ln);
        count *= g_sys_nalpm_master[lchip]->ipv6_couple_mode?2:1;
        break;
    default:
        break;
    }

    return count;
}

STATIC int32
_sys_nalpm2_merge_route_trie(uint8 lchip,
                                  uint8 ln,
                                  uint16 merge_cnt,
                                  sys_nalpm_tcam_item_t* p_prt_tcam_item,
                                  sys_nalpm_tcam_item_t* p_chd_tcam_item)
{
    int32 ret = CTC_E_NONE;
    sys_nalpm_cookie_t cookie;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);

    /*prepare cookie data*/
    sal_memset(&cookie, 0, sizeof(sys_nalpm_cookie_t));

    /*alloc offset*/
    cookie.merge_cnt =  merge_cnt;
    _sys_nalpm2_alloc_offset_array(lchip, ln, p_prt_tcam_item, &cookie);

    cookie.lchip = lchip;
    cookie.p_install_tcam = p_prt_tcam_item;
    cookie.p_chd_tcam = p_chd_tcam_item;

    CTC_ERROR_RETURN(sys_nalpm_trie_traverse (p_prt_tcam_item->trie->trie,
                                              ((LEVEL0 == ln) ? _sys_nalpm2_route_install_element_l0 :
                                              _sys_nalpm2_route_install_element_l1),
                                              (void*)&cookie,
                                              _TRIE_INORDER_TRAVERSE));
    return ret;
}


int32
_sys_nalpm2_write_route_trie(uint8 lchip, uint8 ln, sys_nalpm_tcam_item_t* p_tcam_item, uint8 new_tcam)
{
    uint8 i = 0, j = 0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;

    uint8 do_compact_op = 0;
    uint8 ip_ver = p_tcam_item->p_prefix_info->ip_ver;
    sys_nalpm_cookie_t* p_cookie = NULL;
    sys_nalpm_route_info_t* p_new_route = NULL;

    /*prepare cookie data*/
    _sys_nalpm2_create_cookie(lchip, ln, p_tcam_item, NULL, &p_cookie);

    SYS_NALPM_BUCKET_LOOP(lchip, ln, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (NULL == p_tcam_item->p_ipuc_info_array[i][j])
            {
                continue;
            }

            p_new_route = (sys_nalpm_route_info_t*)p_tcam_item->p_ipuc_info_array[i][j] ;

            _sys_nalpm_write_sram(lchip, ln, p_tcam_item, p_new_route, i , j, 0, p_cookie->ds_snake_root[i]);

        }
    }

    /*write cookie data to hw*/
    _sys_nalpm2_write_route_cookie(lchip, ln, p_tcam_item, NULL, p_cookie);
    mem_free(p_cookie);

    return 0;

}

typedef enum _alpm_cb_merge_type_e {
    ACB_MERGE_INVALID = 0,
    ACB_MERGE_CHILD_TO_PARENT,
    ACB_MERGE_PARENT_TO_CHILD,
    ACB_MERGE_LCHILD_TO_RCHILD
} _alpm_cb_merge_type_t;

#define ACB_REPART_THRESHOLD 8
#define ACB_MERGE_THRESHOLD  8

uint8 _alpm_merge_state[128] = {0};

#define _ALPM_MERGE_CHANGE      0
#define _ALPM_MERGE_UNCHANGE    1


#define ALPM_MERGE_REQD(lchip, vrf_id)              \
        (_alpm_merge_state[vrf_id] != _ALPM_MERGE_UNCHANGE)
#define ALPM_MERGE_STATE_CHKED(lchip, vrf_id)        \
         (_alpm_merge_state[vrf_id] = _ALPM_MERGE_UNCHANGE)
#define ALPM_MERGE_STATE_CHANGED(lchip, vrf_id)     \
        (_alpm_merge_state[vrf_id] = _ALPM_MERGE_CHANGE)


typedef sys_nalpm_prefix_trie_payload_t sys_alpm_pvt_node_t;

#define ALPM_PVT_TRIE(lchip, vrf_id, ip_ver) g_sys_nalpm_master[lchip]->prefix_trie[LEVEL0][ip_ver][vrf_id]
#define PVT_BKT_TRIE(pvt_node)          ((pvt_node)->tcam_item.trie)

int32
sys_nalpm2_get_snake_sram_used(uint8 lchip,
                         uint8 ln,
                         uint8 ip_ver,
                         uint32 vrf_id,
                         sys_alpm_pvt_node_t *pvt_node)
{
    uint32 used_cnt = 0;
    uint8 i = 0, j =0;
    uint8 route_per_snake = 0;
    uint8 snake_entry_cnt = 0;
    sys_nalpm_tcam_item_t* p_tcam_item = NULL;

    p_tcam_item = &pvt_node->tcam_item;

    SYS_NALPM_BUCKET_LOOP(lchip, ln, i, p_tcam_item->sram_type, p_tcam_item->sram_idx, route_per_snake, snake_entry_cnt)
    {
        for (j = 0; j < snake_entry_cnt; j++)
        {
            if (CTC_IS_BIT_SET(NALPM2_BUCKET(lchip, ln, p_tcam_item->sram_idx).bitmap[i], j))
            {
                used_cnt++;
            }
        }
    }

    return used_cnt;
}


STATIC int32
_sys_tsingma_remove_pvt_resource(uint8 lchip, uint8 ln, sys_alpm_pvt_node_t *pvt_node)
{
    ctc_ipuc_param_t ipuc_param;
    int32 ret = 0;
    sal_memset(&ipuc_param, 0, sizeof(ipuc_param));
    ipuc_param.ip_ver = pvt_node->tcam_item.p_prefix_info->ip_ver;

      CTC_ERROR_RETURN(_sys_nalpm2_write_tcam(lchip, &pvt_node->tcam_item, DO_DEL, 0));
    CTC_ERROR_RETURN(_sys_nalpm2_tcam_idx_free(lchip, &ipuc_param, &pvt_node->tcam_item));
    CTC_ERROR_RETURN(_sys_nalpm2_sram_idx_free(lchip, ln,  pvt_node->tcam_item.sram_idx, ipuc_param.ip_ver));

    return ret;
}

STATIC int32
_sys_nalpm2_merge_pvt(uint8 lchip,
                  uint8 ln,
                  sys_alpm_pvt_node_t *src_pvt,
                  sys_alpm_pvt_node_t *dst_pvt,
                  uint32 merge_dir)
{
    int32 ret = CTC_E_NONE;
    uint8 ip_ver = 0;
    uint32 vrf_id = 0;
    uint32 key_len = 0;
    uint8 merge_cnt = 0;
    trie_node_t *tn = NULL;
    sys_alpm_pvt_node_t *prt_pvt = NULL;
    sys_alpm_pvt_node_t *chd_pvt = NULL;

    trie_t *clone_prt_trie = NULL;
    trie_t *clone_chd_trie = NULL;
    sys_nalpm_route_info_t*  new_pivot_pfx_info = NULL;
    sys_nalpm_prefix_trie_payload_t* new_pivot = NULL;


    uint32 key[4] = {0};

    if (merge_dir == ACB_MERGE_PARENT_TO_CHILD)
    {
        prt_pvt = src_pvt;
        chd_pvt = dst_pvt;
    }
    else
    {
        prt_pvt = dst_pvt;
        chd_pvt = src_pvt;
    }

    /* 3. Merge trie */
    ip_ver = chd_pvt->tcam_item.p_prefix_info->ip_ver;
    vrf_id = chd_pvt->tcam_item.p_prefix_info->vrf_id;


    merge_cnt = PVT_BKT_TRIE(chd_pvt)->trie->count;

    CTC_ERROR_RETURN(sys_nalpm_trie_clone(PVT_BKT_TRIE(prt_pvt), &clone_prt_trie));
    CTC_ERROR_RETURN(sys_nalpm_trie_clone(PVT_BKT_TRIE(chd_pvt), &clone_chd_trie));

    sal_memset(key, 0 , sizeof(key));
    sal_memcpy(key, chd_pvt->tcam_item.p_prefix_info->ip, IP_ADDR_SIZE(ip_ver));
    key_len = chd_pvt->tcam_item.p_prefix_info->tcam_masklen;

    CTC_ERROR_GOTO(trie_merge(PVT_BKT_TRIE(prt_pvt), PVT_BKT_TRIE(chd_pvt)->trie,  key, key_len), ret, error1);

    if (merge_dir == ACB_MERGE_LCHILD_TO_RCHILD)
    {
        uint32 pfx[4] = {0};
        uint32 prefix_len = 0;
        uint32 key1[4] = {0};
        uint32 key_len1 = 0;
        ctc_ipuc_param_t ipuc_param;
          uint16 route_info_size = 0;

        sys_trie_find_lpm_prefix(PVT_BKT_TRIE(prt_pvt), pfx, &prefix_len);

        /*����lpm parent ǰ׺��Ϣ������tcam*/
        sal_memset(&ipuc_param, 0, sizeof(ipuc_param));
        ipuc_param.ip_ver = prt_pvt->tcam_item.p_prefix_info->ip_ver;

        route_info_size = NALPM2_INFO_SIZE(ip_ver);
        new_pivot_pfx_info = mem_malloc(MEM_IPUC_MODULE, route_info_size);
        if (NULL == new_pivot_pfx_info)
        {
            ret =  CTC_E_NO_MEMORY;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            goto error1;
        }

       // sal_printf("1. chd_pvt trie:%p, count:%d route_info_size:%d\n",  chd_pvt->tcam_item.trie, chd_pvt->tcam_item.trie->trie->count, route_info_size);
        sal_memset(new_pivot_pfx_info, 0, route_info_size);
       //  sal_printf("2. chd_pvt trie:%p, count:%d \n",  chd_pvt->tcam_item.trie, chd_pvt->tcam_item.trie->trie->count);

        new_pivot = mem_malloc(MEM_IPUC_MODULE, sizeof(sys_nalpm_prefix_trie_payload_t));
        if (NULL == new_pivot)
        {
            ret =  CTC_E_NO_MEMORY;
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "---[%d]--- \r\n", __LINE__);
            goto error2;
        }
        sal_memset(new_pivot, 0, sizeof(sys_nalpm_prefix_trie_payload_t));
        sal_memcpy(&new_pivot->tcam_item , &prt_pvt->tcam_item, sizeof(sys_nalpm_tcam_item_t));
        sal_memcpy(new_pivot_pfx_info, prt_pvt->tcam_item.p_prefix_info, route_info_size);
        new_pivot->tcam_item.p_prefix_info = new_pivot_pfx_info;

        new_pivot->tcam_item.p_prefix_info->tcam_masklen = prefix_len;
        sal_memcpy(new_pivot->tcam_item.p_prefix_info->ip, pfx, sizeof(pfx));


        ret = _sys_nalpm2_tcam_idx_alloc(lchip, &ipuc_param, &(new_pivot->tcam_item));
        if (CTC_E_NONE != ret)
        {
            goto error3;
        }

        /*update new snake sram entry*/
        _sys_nalpm2_merge_route_trie(lchip, ln, merge_cnt, &new_pivot->tcam_item, &chd_pvt->tcam_item);


        if (NALPM2_BUCKET_MGR_EN(lchip, ip_ver))
        {
            /*update chd_pvt bucket*/
            _sys_nalpm2_bucket_list_update(lchip, ln, chd_pvt->tcam_item.sram_idx, -merge_cnt);

            /*update prt_pvt bucket*/
            _sys_nalpm2_bucket_list_update(lchip, ln, new_pivot->tcam_item.sram_idx, merge_cnt);

        }

         sys_nalpm_trie_insert(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), pfx, NULL, prefix_len, (trie_node_t *) new_pivot, 0);
        _sys_nalpm2_write_route_trie(lchip, ln, &new_pivot->tcam_item, 0);
         _sys_nalpm2_write_tcam(lchip, &(new_pivot->tcam_item), DO_ADD, 0);

        _sys_nalpm2_write_tcam(lchip, &prt_pvt->tcam_item, DO_DEL, 0);
        _sys_nalpm2_tcam_idx_free(lchip, &ipuc_param, &prt_pvt->tcam_item);
        /* delete child pvt from trie */
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key, key_len, &tn);

        /* delete parent pvt from trie */
        sal_memcpy(key1, prt_pvt->tcam_item.p_prefix_info->ip, IP_ADDR_SIZE(ip_ver));
        key_len1 = prt_pvt->tcam_item.p_prefix_info->tcam_masklen;
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key1, key_len1, &tn);
        mem_free(prt_pvt->tcam_item.p_prefix_info);
        mem_free(prt_pvt);

    }
    else
    {
        /*update new snake sram entry*/
        _sys_nalpm2_merge_route_trie(lchip, ln, merge_cnt, &prt_pvt->tcam_item, &chd_pvt->tcam_item);

        merge_cnt = PVT_BKT_TRIE(chd_pvt)->trie->count;

        if (NALPM2_BUCKET_MGR_EN(lchip, ip_ver))
        {
            /*update chd_pvt bucket*/
            _sys_nalpm2_bucket_list_update(lchip, ln, chd_pvt->tcam_item.sram_idx, -merge_cnt);

            /*update prt_pvt bucket*/
            _sys_nalpm2_bucket_list_update(lchip, ln,  prt_pvt->tcam_item.sram_idx, merge_cnt);

        }

        _sys_nalpm2_write_route_trie(lchip, ln, &prt_pvt->tcam_item, 0);

       /* Destroy child pvt from trie, tn is chd_pvt */
        trie_delete(ALPM_PVT_TRIE(lchip, vrf_id, ip_ver), key, key_len, &tn);
    }

    _sys_nalpm2_write_tcam(lchip, &chd_pvt->tcam_item, DO_DEL, 0);

    /* 6.remove prefix  resource*/
    _sys_tsingma_remove_pvt_resource(lchip, ln, chd_pvt);

    /*remove source trie*/
    sys_nalpm_trie_destroy(PVT_BKT_TRIE(chd_pvt));
    mem_free(chd_pvt->tcam_item.p_prefix_info);
    mem_free(chd_pvt);

    if (clone_prt_trie)
    {
        sys_nalpm_trie_clear(clone_prt_trie->trie);
        sys_nalpm_trie_destroy(clone_prt_trie);
    }
    if (clone_chd_trie)
    {
        sys_nalpm_trie_clear(clone_chd_trie->trie);
        sys_nalpm_trie_destroy(clone_chd_trie);
    }

    return ret;


error3:
    mem_free(new_pivot);

error2:
    mem_free(new_pivot_pfx_info);

error1:

    sys_nalpm_trie_clear(prt_pvt->tcam_item.trie->trie);
    sys_nalpm_trie_destroy(prt_pvt->tcam_item.trie);
    sys_nalpm_trie_destroy(chd_pvt->tcam_item.trie);
    prt_pvt->tcam_item.trie = clone_prt_trie;
    chd_pvt->tcam_item.trie = clone_chd_trie;
    return ret;
}


STATIC int32
sys_nalpm2_merge_cb(trie_node_t *ptrie, trie_node_t *trie,
                 trie_traverse_states_e_t *state, void *info)
{
    int32 rv = 0;
    uint32 lchip = 0;
    uint32 prt_cnt = 0;
    uint32 chd_cnt = 0;
    uint32 vrf_id = 0;
    uint8 ln = 0;
    uint8 ip_ver = 0;

    sys_alpm_pvt_node_t *prt_pvt, *chd_pvt, *src_pvt, *dst_pvt;
    sys_alpm_cb_merge_ctrl_t *merge_ctrl;
    _alpm_cb_merge_type_t merge_dir = ACB_MERGE_INVALID;

    prt_pvt = (sys_alpm_pvt_node_t *)ptrie;
    chd_pvt = (sys_alpm_pvt_node_t *)trie;
    if (!prt_pvt)
    {
        return CTC_E_NONE;
    }

    if (PVT_BKT_TRIE(prt_pvt)->trie == NULL)
    {
        merge_dir = ACB_MERGE_PARENT_TO_CHILD;
    }

    if (PVT_BKT_TRIE(chd_pvt)->trie == NULL)
    {
        merge_dir = ACB_MERGE_CHILD_TO_PARENT;
    }

    merge_ctrl = (sys_alpm_cb_merge_ctrl_t *)info;
    lchip   = merge_ctrl->lchip;
    ip_ver = merge_ctrl->ip_ver;
    vrf_id = merge_ctrl->vrf_id;

    if (merge_dir == ACB_MERGE_INVALID)
    {
        uint32 prt_entrys = 0;
        uint32 chd_entrys = 0;

        prt_cnt = _sys_nalpm2_get_bucket_entry_cnt(lchip, ln,  prt_pvt->tcam_item.sram_type);
        chd_cnt = _sys_nalpm2_get_bucket_entry_cnt(lchip, ln, chd_pvt->tcam_item.sram_type);

        prt_entrys = prt_cnt - sys_nalpm2_get_snake_sram_used(lchip, ln, ip_ver, vrf_id, prt_pvt);
        chd_entrys = chd_cnt - sys_nalpm2_get_snake_sram_used(lchip, ln, ip_ver, vrf_id, chd_pvt);


        if (PVT_BKT_TRIE(chd_pvt)->trie->count <= prt_entrys)
        {
            merge_dir   = ACB_MERGE_CHILD_TO_PARENT;
        }
        else if (PVT_BKT_TRIE(prt_pvt)->trie->count <= chd_entrys)
        {
            merge_dir   = ACB_MERGE_PARENT_TO_CHILD;
        }
        else
        {
            return CTC_E_NONE;
        }

    }

    if (merge_dir == ACB_MERGE_PARENT_TO_CHILD)
    {
        src_pvt = prt_pvt;
        dst_pvt = chd_pvt;
    }
    else
    {
        src_pvt = chd_pvt;
        dst_pvt = prt_pvt;
    }

    rv = _sys_nalpm2_merge_pvt(lchip, ln, src_pvt, dst_pvt, merge_dir);

    if (rv < 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "alpm merge failed rv %d\n", rv);
        return rv;
    }

    *state = TRIE_TRAVERSE_STATE_DELETED;

    ++merge_ctrl->merge_count;

    return CTC_E_NONE;

}


int32
sys_nalpm2_merge_lr_cb(trie_node_t *ptrie, trie_node_t * trie, trie_traverse_states_e_t *state, void *info)
{
    int32 ret = 0;
    uint32 lchip = 0;
    uint8 i = 0;
    trie_node_t* son[2] = {NULL};
    sys_alpm_cb_merge_ctrl_t *merge_ctrl;
    sys_nalpm_prefix_trie_payload_t*  leaf0;
    sys_nalpm_prefix_trie_payload_t*  leaf1;
    uint8 capacity = 0;
    uint32 no_sram_idx = 0;
    uint8 ln = 0;
    son[0] = trie->child[0].child_node;
    son[1] = trie->child[1].child_node;

    if(NULL == son[0] || NULL == son[1])
    {
        return CTC_E_NONE;
    }

    if(trie->type == INTERNAL && son[0]->type == INTERNAL && son[1]->type == INTERNAL
        && son[0]->count == 2 && son[1]->count == 2
        && son[0]->child[0].child_node->type == PAYLOAD && son[0]->child[1].child_node->type == PAYLOAD
        && son[1]->child[0].child_node->type == PAYLOAD && son[1]->child[1].child_node->type == PAYLOAD)
    {
        merge_ctrl = (sys_alpm_cb_merge_ctrl_t *)info;
        lchip  = merge_ctrl->lchip;
         no_sram_idx = merge_ctrl->sram_idx;

        for(i = 0; i < 2; i++)
        {
            leaf0 = (sys_nalpm_prefix_trie_payload_t*)son[i]->child[0].child_node;
            leaf1 = (sys_nalpm_prefix_trie_payload_t*)son[i]->child[1].child_node;

            capacity = _sys_nalpm2_get_bucket_entry_cnt(lchip, ln, leaf0->tcam_item.sram_type);

            if (leaf0->node.skip_len != 0 || leaf1->node.skip_len != 0 )
            {
                continue;
            }

            if (leaf0->tcam_item.p_prefix_info->tcam_masklen != leaf1->tcam_item.p_prefix_info->tcam_masklen)
            {
                continue;
            }

            if (leaf0->tcam_item.trie->trie->count + leaf1->tcam_item.trie->trie->count > capacity)
            {
                continue;
            }

            if (leaf1->tcam_item.sram_idx == no_sram_idx || leaf0->tcam_item.sram_idx == no_sram_idx)
            {
                continue;
            }


#if 0
            sal_printf("-----------------------------------------\n");
            sal_printf("leaf0 cnt:%d leaf0 cnt:%d capacity:%d\n", leaf0->tcam_item.trie->trie->count, leaf1->tcam_item.trie->trie->count, capacity);
#endif

            ret = _sys_nalpm2_merge_pvt(lchip, ln, leaf1, leaf0, ACB_MERGE_LCHILD_TO_RCHILD);

            if (ret != CTC_E_NONE)
            {
                return ret;
            }
            else
            {
                ++merge_ctrl->merge_count;
            }

            *state = TRIE_TRAVERSE_STATE_DONE;

        }

    }
    return CTC_E_NONE;
}


int32
sys_nalpm2_merge_prefix(uint8 lchip, uint32 vrf_id, uint32 sram_idx)
{
    int32 rv = CTC_E_NONE;

    sys_alpm_cb_merge_ctrl_t merge_ctrl;
    trie_traverse_states_e_t state = TRIE_TRAVERSE_STATE_NONE;

    if( g_sys_nalpm_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6][vrf_id]&&
       g_sys_nalpm_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6][vrf_id]->trie)
    {
        sal_memset(&merge_ctrl, 0, sizeof(merge_ctrl));
        merge_ctrl.lchip     = lchip;
        merge_ctrl.vrf_id   = vrf_id;
        merge_ctrl.ip_ver   = CTC_IP_VER_6;
        merge_ctrl.sram_idx = sram_idx;

        rv=  sys_nalpm_trie_traverse_lr(g_sys_nalpm_master[lchip]->prefix_trie[LEVEL0][CTC_IP_VER_6][vrf_id]->trie, &state,
                                        sys_nalpm2_merge_lr_cb, &merge_ctrl);

        if (rv < 0)
        {
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "sys_nalpm_auto_merge failed, vrf_id %d rv %d.\n", vrf_id, rv);
        }

        g_sys_nalpm_master[lchip]->merge_cnt += merge_ctrl.merge_count;
    }
    return rv;
}

int32
sys_nalpm2_merge(uint8 lchip, uint32 vrf_id, uint8 ip_ver)
{
    int32 rv = CTC_E_NONE;
    trie_t *pvt_trie;
    sys_alpm_cb_merge_ctrl_t merge_ctrl;

    LCHIP_CHECK(lchip);
    CTC_IP_VER_CHECK(ip_ver);
    SYS_IP_VRFID_CHECK(vrf_id);

    SYS_NALPM2_INIT_CHECK;

    pvt_trie = ALPM_PVT_TRIE(lchip, vrf_id, ip_ver);

    if (!ALPM_MERGE_REQD(lchip, vrf_id) ||
        pvt_trie == NULL ||
    pvt_trie->trie == NULL || MERGE_NO_RESOURCE == g_sys_nalpm_master[lchip]->frag_arrange_status[ip_ver])
    {
        return CTC_E_NONE;
    }

    sal_memset(&merge_ctrl, 0, sizeof(merge_ctrl));
    merge_ctrl.lchip     = lchip;
    merge_ctrl.vrf_id   = vrf_id;
    merge_ctrl.ip_ver   = ip_ver;


    rv = sys_nalpm_trie_traverse2(pvt_trie, sys_nalpm2_merge_cb, &merge_ctrl,  _TRIE_POSTORDER_TRAVERSE);
    if (rv < 0)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_ERROR, "Logic bucket merge failed, ip_ver %d vrf_id %d rv %d.\n", ip_ver, vrf_id, rv);
    }

    if (merge_ctrl.merge_count == 0)
    {
        rv = CTC_E_NO_RESOURCE;
    }

    return rv;
}

int32
_sys_nalpm2_dump_route(uint8 i, sys_nalpm_route_info_t* p_ipuc_data)
{
    char buf[CTC_IPV6_ADDR_STR_LEN];

    NALPM2_GEN_IP_STR(buf, p_ipuc_data->ip_ver, p_ipuc_data->ip, p_ipuc_data->route_masklen);

    if (p_ipuc_data->ip_ver == CTC_IP_VER_4)
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-28s\n", p_ipuc_data->hw_position[0], p_ipuc_data->hw_position[1], buf);
    }
    else
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "[%-2d,%-2d] %-44s\n", p_ipuc_data->hw_position[0], p_ipuc_data->hw_position[1], buf);
    }

    return 0;
}

int32
sys_tingma_nalpm_dump_trie(uint8 lchip, sys_nalpm_tcam_item_t *p_tcam_item)
{
    trie_dump_node_t dump_node;
    dump_node.father = p_tcam_item->trie->trie;
    dump_node.father_lvl = 0;
    dump_node.root =  p_tcam_item->trie->trie;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "TcamIdx:%d SramIdx:%d\n", p_tcam_item->tcam_idx, p_tcam_item->sram_idx);

    sys_nalpm_trie_traverse(p_tcam_item->trie->trie, _sys_nalpm2_dump_route_trie_node, &dump_node, _TRIE_DUMP_TRAVERSE);

    return 0;
}

int32
sys_nalpm2_show_bucket_usage(uint8 lchip, uint8 ln, uint8 fmt)
{
    uint8 i = 0;
    uint8 j = 0;
    ctc_list_pointer_t *p_list = NULL;
    ctc_list_pointer_node_t *p_node = NULL;
    sys_nalpm_bucket_t *p_bucket = NULL;
    SYS_NALPM2_INIT_CHECK;

    for (i = 0; i < NALPM2_BUCKET_FMT_MAX(lchip, ln, fmt) - 1; i++)
    {
        p_list = &NALPM2_BUCKET_DB(lchip, ln).bkt_use_list[i];

        if (0 == CTC_LIST_POINTER_COUNT(p_list))
        {
            continue;
        }

        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Cnt %d usage list\n", i);

        CTC_LIST_POINTER_LOOP(p_node, p_list)
        {
            p_bucket = (sys_nalpm_bucket_t*) p_node;

            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Sram Index: %d, Sub Bucket:%d\n", p_bucket->sram_idx, p_bucket->sub_bkt);
            SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "use_cnt: %d\n", p_bucket->use_cnt);

            for (j = 0; j < NALPM2_BUKCET_SNAKE_NUM(lchip, ln); j++ )
            {
                SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_DUMP, "Snake %d bitmap: 0x%x\n",j,  p_bucket->bitmap[j]);
            }
        }

    }

    return CTC_E_NONE;
}

int32
sys_nalpm2_get_route_info(uint8 lchip, ctc_ipuc_param_t* p_ipuc_param, uint32* tcam_index)
{
    sys_nalpm_route_info_t*  p_route_info = NULL;
    sys_nalpm_route_store_info_t lkp_rlt;
    sys_nalpm_route_store_info_t *p_lkp_rlt = &lkp_rlt;
    uint8 ip_ver = 0;
    int32 ret = CTC_E_NONE;
    //TODO
    uint8 ln = 0;

    SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_FUNC, "%s()\n",__FUNCTION__);
    SYS_NALPM2_INIT_CHECK;

    /* prepare data */
    ip_ver = p_ipuc_param->ip_ver;

    p_route_info = mem_malloc2(MEM_IPUC_MODULE, NALPM2_INFO_SIZE(ip_ver), sys_nalpm_route_info_t);
    if(NULL == p_route_info)
    {
        return CTC_E_NO_MEMORY;
    }

    sal_memset(p_route_info, 0 , (NALPM2_INFO_SIZE(ip_ver)));
    p_route_info->ip_ver = ip_ver;
    sal_memcpy(p_route_info->ip, &p_ipuc_param->ip, IP_ADDR_SIZE(ip_ver));
    p_route_info->route_masklen = p_ipuc_param->masklen;
    p_route_info->vrf_id = p_ipuc_param->vrf_id;
    //SYS_IP_V6_SORT(p_route_info);

    /* 1. lookup sw node */
    ret = _sys_nalpm2_route_lkp( lchip, ln , p_route_info,p_lkp_rlt);
    mem_free(p_route_info);
    if(ret < 0 || !p_lkp_rlt->tcam_hit || (!p_lkp_rlt->sram_hit[LEVEL1] && p_ipuc_param->masklen != 0))
    {
        SYS_IPUC_DBG_OUT(CTC_DEBUG_LEVEL_PARAM, "(%d)   can't find  router\n",__LINE__);
        return CTC_E_NOT_EXIST;
    }

    *tcam_index = p_lkp_rlt->p_tcam_item->tcam_idx;

    return CTC_E_NONE;
}

int32
sys_nalpm2_show_sram_free(uint8 lchip, uint8 ln)
{
    uint32 sram_idx = 0;
    uint8 i = 0;

    for (sram_idx = 0; sram_idx < NALPM2_BUCKET_DB(lchip, ln).real_bkt_depth; sram_idx++)
    {
        for (i = 0; i < NALPM2_BUKCET_SNAKE_NUM(lchip, ln); i++)
        {
            if (NALPM2_BUCKET(lchip, ln, sram_idx).bitmap[i] != _sys_nalpm2_get_snake_bitwdith(lchip, SYS_NALPM2_SRAM_TYPE_V4_32, i))
            {
                sal_printf("sram idx:%d bitmap[%d]:0x%x\n", sram_idx, i, NALPM2_BUCKET(lchip, ln, sram_idx).bitmap[i]);
            }
        }
    }

    return 0;
}

#endif
